
/*关于按键：
遍历是一个简单的事，定义好parent，child, dn_sibble, up_sibble即可。
处理复杂的是叶子菜单项的定义（定义那些操作属于一个叶子菜单项，如定义了CAL_In）和处理。
工作量大，要编写每个叶子菜单项。
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>


#include "bsp.h"
#include "menu_seg.h"
#include "key.h"
#include "threads.h"
#include "dbgUart.h"
#include "parameter.h"
#include "weight_polyline.h"
#include "ds28e25.h"
#include "preset_point.h"


extern uint8_t flag_para_update_adc;
extern uint8_t flag_para_update_dac;
extern uint8_t flag_para_update_com;		//通信参数。
extern uint8_t flag_para_update_fir;
extern uint8_t flag_ma_cal;

extern int32_t para_to_flash_2(uint32_t );

extern const char str_ver[];

extern PRESET_P preset_point[];				//预置点（限制点）


const uint16_t _tbl_1d[]= {1,2,5, 10,20,50, 100,200,500, 1000,2000,5000,-1};
//const uint32_t _tbl_plc_baud[]={9600,14400,19200,28800,38400,57600,76800,96000,115200,160000,200000,-1};
//const char* tbl_plc_fmt[]={/*" 7-E-1", " 7-O-1",*/ " 8-n-2", " 8-O-1", " 8-E-1", " 8-n-1", ""};
const uint16_t _tbl_adc_sps[]={120, 480, 960, -1};

//#define ANA_4_20								"  4-20"	
//#define ANA_0_20								"  0-20"
//#define ANA_0_24								"  0-24"
//#define ANA_0_5									"   0-5"
//#define ANA_0_10								"  0-10"
//#define ANA_5_5									"  -5-5"
//#define ANA_10_10								" 10-10"
const char* _tbl_ana_out[]={ANA_4_20_STR, ANA_0_20_STR, ANA_0_24_STR, ANA_0_5_STR, ANA_0_10_STR, ANA_5_5_STR, ANA_10_10_STR, ANA_I_STR, ANA_V_STR, ""};

static int32_t pass_compare(char* p);
static int32_t pass_setup_compare(char* p);
static int32_t pass_compare2(char* p1, char* p2);
static int32_t pass_compare_rst(char* p);
static void show_pt(uint32_t pos, char* p);
static void show_1d(uint32_t dat_1d, char* p);
static void show_val(int32_t val, char* p);
static void show_duration(int32_t val, char* p);
static void show_val_5(int32_t val, char* p);
static void show_output_i_u(uint32_t val, char* p);
static void show_baud(uint32_t val, char* p);
static void show_com_baud(uint32_t val, char* p);
static void show_com_mode(uint32_t val, char* p);
static void show_com_format(uint32_t val, char* p);
static void show_hilo(uint32_t val, char* p);
static void show_com_interval(uint32_t val, char* p);

static void inc_1d(uint8_t* p);
static void dec_1d(uint8_t* p);

static uint32_t find_1d_idx(uint16_t dat);
static uint32_t find_cell_baud_idx(uint32_t dat);
static uint32_t find_cell_fmt_idx(char* p);

static uint32_t find_int16_cnt(const uint16_t* tbl);		//查找uint16_t[]数组的尾巴，特征是-1。
static uint32_t find_int32_cnt(const uint32_t* tbl);		//查找uint32_t[]数组的尾巴，特征是-1。
static uint32_t find_string_cnt(const char* *tbl_str);		//查找字符串[]数组的尾巴，特征是""。

void key_F1_4(MSG_U msg);		//功能同key_Fn()，增加了小数点。



/*叶子菜单项的按键处理函数。
*/
//void test_io_child_key_Fn(uint16_t key);
//void test_chilid_key_Fn(uint16_t key);
void leaf_Fn_test_io_child(MSG_U msg);
void leaf_Fn_test_child(MSG_U msg);

void enter_Fn_setup_in(void);
void setup_in_leaf_Fn(MSG_U msg);
void setup_F11_leaf_Fn(MSG_U msg);
void setup_F12_leaf_Fn(MSG_U msg);
void setup_F13_leaf_Fn(MSG_U msg);
void setup_F14_leaf_Fn(MSG_U msg);
void setup_F15_leaf_Fn(MSG_U msg);
void setup_F16_leaf_Fn(MSG_U msg);
void setup_F17_leaf_Fn(MSG_U msg);

void setup_F21_leaf_Fn(MSG_U msg);
void setup_F22_leaf_Fn(MSG_U msg);
void setup_F23_leaf_Fn(MSG_U msg);
void setup_F24_leaf_Fn(MSG_U msg);
void setup_F25_leaf_Fn(MSG_U msg);
void setup_F26_leaf_Fn(MSG_U msg);

void setup_F31_leaf_Fn(MSG_U msg);
void setup_F32_leaf_Fn(MSG_U msg);
void setup_F33_leaf_Fn(MSG_U msg);
void setup_F34_leaf_Fn(MSG_U msg);
void setup_F35_leaf_Fn(MSG_U msg);

void setup_F41_leaf_Fn(MSG_U msg);
void setup_F42_leaf_Fn(MSG_U msg);

//void leaf_Fn_ma_cal(MSG_U  msg);
void leaf_Fn_ma_cal_4K(MSG_U msg);		//4.000mA  -> 4K
void leaf_Fn_ma_cal_12K(MSG_U msg);		//12.000mA -> 12K
void leaf_Fn_ma_cal_20K(MSG_U msg);		//20.000mA -> 20K
void leaf_Fn_ma_cal_24K(MSG_U msg);		//24.000mA -> 24K


void leaf_Fn_cal_in(MSG_U msg);
void leaf_Fn_cal_pt(MSG_U msg);
void leaf_Fn_cal_cp(MSG_U msg);
void leaf_Fn_cal_t(MSG_U msg);			//零点mv值
void leaf_Fn_cal_load1(MSG_U msg);		//有砝码标定第1点的叶子菜单项函数。
void leaf_Fn_cal_load2(MSG_U msg);		//有砝码标定第2点的叶子菜单项函数。
void leaf_Fn_cal_load3(MSG_U msg);		//有砝码标定第3点的叶子菜单项函数。
void leaf_Fn_cal_load4(MSG_U msg);		//有砝码标定第4点的叶子菜单项函数。
void leaf_Fn_cal_1d(MSG_U msg);
void leaf_Fn_cal_siocal(MSG_U msg);
void leaf_Fn_cal_pass(MSG_U msg);
void leaf_Fn_cal_RdP(MSG_U msg);		//CAL下读取DS28E中保存的标定参数：point[]，最大量程。
void leaf_Fn_cal_SaP(MSG_U msg);		//CAL下保存标定参数（point[]，最大量程）到DS28E。


static void enter_Fn_test_io(void);



/*已优化：P1和P2，P3，P4很相似。
通过菜单项成员变量id来识别。
!!spoint仅用来配置限制值，out1/2使用这些配置。
*/
static void leaf_Fn_spoint_P11(MSG_U msg);
static void leaf_Fn_spoint_P12(MSG_U msg);
static void leaf_Fn_spoint_P13(MSG_U msg);
static void leaf_Fn_spoint_P14(MSG_U msg);
static void leaf_Fn_spoint_P15(MSG_U msg);

//static void leaf_Fn_spoint_P21(MSG_U msg);
//static void leaf_Fn_spoint_P22(MSG_U msg);
//static void leaf_Fn_spoint_P23(MSG_U msg);
//static void leaf_Fn_spoint_P24(MSG_U msg);
//static void leaf_Fn_spoint_P25(MSG_U msg);

//static void leaf_Fn_spoint_P31(MSG_U msg);
//static void leaf_Fn_spoint_P32(MSG_U msg);
//static void leaf_Fn_spoint_P33(MSG_U msg);
//static void leaf_Fn_spoint_P34(MSG_U msg);
//static void leaf_Fn_spoint_P35(MSG_U msg);

//static void leaf_Fn_spoint_P41(MSG_U msg);
//static void leaf_Fn_spoint_P42(MSG_U msg);
//static void leaf_Fn_spoint_P43(MSG_U msg);
//static void leaf_Fn_spoint_P44(MSG_U msg);
//static void leaf_Fn_spoint_P45(MSG_U msg);


static void leaf_Fn_io_out1(MSG_U msg);
static void leaf_Fn_io_out2(MSG_U msg);
static void leaf_Fn_io_in1(MSG_U msg);

static void leaf_Fn_hold_H1(MSG_U msg);		//没有H1n子菜单。
static void leaf_Fn_hold_H2(MSG_U msg);
static void leaf_Fn_hold_H3(MSG_U msg);



static void leaf_Fn_rst(MSG_U msg);


//
static void init_top_menu(void);

static void init_Fn_menu(void);
static void init_F1n_menu(void);
static void init_F2n_menu(void);
static void init_F3n_menu(void);
static void init_F4n_menu(void);

void init_ma_cal_menu(void);				//mA修正。


static void init_CALn_menu(void);

static void init_Pn_menu(void);
static void init_P1n_menu(void);
static void init_P2n_menu(void);
static void init_P3n_menu(void);
static void init_P4n_menu(void);

static void init_Hn_menu(void);
static void init_IOn_menu(void);

static void init_test_io_menu(void);
static void init_test_menu(void);
static void init_rst_menu(void);



//菜单项（不用添加.f_enter=NULL，因为static 类型变量，默认为0，即NULL）
static MENU_ITEM setup=		{.id= 1, .content="setUp  ", .f_enter=NULL};
static MENU_ITEM cal=  		{.content="Cal    ", .f_enter=NULL};
static MENU_ITEM spoint=	{.content="spoint ", .f_enter=NULL};
static MENU_ITEM hold=		{.content="Hold   ", .f_enter=NULL};
static MENU_ITEM io_def=	{.content="io dEF ", .f_enter=NULL};
static MENU_ITEM test_io=	{.content="testio ", .f_enter=NULL};
static MENU_ITEM test=		{.content="test   ", .f_enter=NULL};
static MENU_ITEM rst=		{.content="rst    ", .f_enter=NULL};

static MENU_ITEM FIN=		{.content="PASS   ", .f_enter=NULL};
static MENU_ITEM F1=		{.content="F1     ", .f_enter=NULL};
static MENU_ITEM F2=		{.content="F2     ", .f_enter=NULL};
static MENU_ITEM F3=		{.content="F3     ", .f_enter=NULL};
static MENU_ITEM F4=		{.content="F4     ", .f_enter=NULL};
//static MENU_ITEM F5=		{.content="F5     "};
//static MENU_ITEM F6=		{.content="F6     "};
//static MENU_ITEM F7=		{.content="F7     "};

static MENU_ITEM mA_Cal=		{.content="i 4000 ", .f_enter=NULL};	//
static MENU_ITEM mA_Cal_4K=		{.content="i 4000 ", .f_enter=NULL};
static MENU_ITEM mA_Cal_12K=	{.content="i12000 ", .f_enter=NULL};
static MENU_ITEM mA_Cal_20K=	{.content="i20000 ", .f_enter=NULL};
static MENU_ITEM mA_Cal_24K=	{.content="i24000 ", .f_enter=NULL};	

static MENU_ITEM F11={.content="F1.1   ", .f_enter=NULL};
static MENU_ITEM F12={.content="F1.2   ", .f_enter=NULL};
static MENU_ITEM F13={.content="F1.3   ", .f_enter=NULL};
static MENU_ITEM F14={.content="F1.4   ", .f_enter=NULL};
static MENU_ITEM F15={.content="F1.5   ", .f_enter=NULL};
static MENU_ITEM F16={.content="F1.6   ", .f_enter=NULL};
static MENU_ITEM F17={.content="F1.7   ", .f_enter=NULL};

static MENU_ITEM F21={.content="F2.1   ", .f_enter=NULL};
static MENU_ITEM F22={.content="F2.2   ", .f_enter=NULL};
static MENU_ITEM F23={.content="F2.3   ", .f_enter=NULL};
static MENU_ITEM F24={.content="F2.4   ", .f_enter=NULL};
static MENU_ITEM F25={.content="F2.5   ", .f_enter=NULL};
static MENU_ITEM F26={.content="F2.6   ", .f_enter=NULL};

static MENU_ITEM F31={.content="F3.1   "};
static MENU_ITEM F32={.content="F3.2   "};
static MENU_ITEM F33={.content="F3.3   "};
static MENU_ITEM F34={.content="F3.4   "};
static MENU_ITEM F35={.content="F3.5   "};

static MENU_ITEM F41={.content="F4.1   "};
static MENU_ITEM F42={.content="F4.2   "};

static MENU_ITEM CAL_In=	{.content="PASS   "};	//
static MENU_ITEM CAL_Pt=	{.content="Pt     "};
static MENU_ITEM CAL_1d=	{.content="1d     "};
static MENU_ITEM CAL_CP=	{.content="CP     "};
static MENU_ITEM CAL_t=		{.content="t      "};
//static MENU_ITEM CAL_O=		{.content="O      "};
static MENU_ITEM CAL_Load1=	{.content="Load1  "};
static MENU_ITEM CAL_Load2=	{.content="Load2  "};
static MENU_ITEM CAL_Load3=	{.content="Load3  "};
static MENU_ITEM CAL_Load4=	{.content="Load4  "};
static MENU_ITEM CAL_Sen=	{.content="Sen    "};
//static MENU_ITEM CAL_C=		{.content="C      "};
static MENU_ITEM CAL_Siocal={.content="Siocal "};
static MENU_ITEM CAL_Pass=	{.content="Pass   "};
static MENU_ITEM CAL_RdP=	{.content="rd P   "};		//读取单线芯片的资料
static MENU_ITEM CAL_SaP=	{.content="SA P   "};		//保存单线芯片的资料


static MENU_ITEM P1={.content="P1     "};
static MENU_ITEM P2={.content="P2     "};
static MENU_ITEM P3={.content="P3     "};
static MENU_ITEM P4={.content="P4     "};

static MENU_ITEM P11={.id=11, .content="P1.1   "};
static MENU_ITEM P12={.id=12, .content="P1.2   "};
static MENU_ITEM P13={.id=13, .content="P1.3   "};
static MENU_ITEM P14={.id=14, .content="P1.4   "};
static MENU_ITEM P15={.id=15, .content="P1.5   "};

static MENU_ITEM P21={.id=21, .content="P2.1   "};
static MENU_ITEM P22={.id=22, .content="P2.2   "};
static MENU_ITEM P23={.id=23, .content="P2.3   "};
static MENU_ITEM P24={.id=24, .content="P2.4   "};
static MENU_ITEM P25={.id=25, .content="P2.5   "};

static MENU_ITEM P31={.id=31, .content="P3.1   "};
static MENU_ITEM P32={.id=32, .content="P3.2   "};
static MENU_ITEM P33={.id=33, .content="P3.3   "};
static MENU_ITEM P34={.id=34, .content="P3.4   "};
static MENU_ITEM P35={.id=35, .content="P3.5   "};

static MENU_ITEM P41={.id=41, .content="P4.1   "};
static MENU_ITEM P42={.id=42, .content="P4.2   "};
static MENU_ITEM P43={.id=43, .content="P4.3   "};
static MENU_ITEM P44={.id=44, .content="P4.4   "};
static MENU_ITEM P45={.id=45, .content="P4.5   "};

static MENU_ITEM H1={.content="H1     "};
static MENU_ITEM H2={.content="H2     "};
static MENU_ITEM H3={.content="H3     "};

static MENU_ITEM IO_Out1={.content="oUt1"};
static MENU_ITEM IO_Out2={.content="oUt2"};
static MENU_ITEM IO_In1={.content="in1"};

static MENU_ITEM test_io_chilid=	{.content="F   FF"};
static MENU_ITEM test_chilid=	{.content="888888"};

static MENU_ITEM rst_chilid=	{.content="PASS  "};



uint32_t update_para_to_flash=0;		//是否更新参数到FLASH。准备作废。
MENU_ITEM* cur_item= NULL;				//当前菜单项（遍历菜单项时用）。



/*初始化菜单项（所有级的菜单项）。
*/
void menu_init(void)
{
	init_top_menu();
	
	//setup菜单
	init_Fn_menu();	
	init_F1n_menu();	
	init_F2n_menu();
	init_F3n_menu();
	init_F4n_menu();
	
	init_ma_cal_menu();

	//cal菜单
	init_CALn_menu();

	init_Pn_menu();

	init_Hn_menu();
	init_IOn_menu();
	
	init_test_io_menu();
	init_test_menu();
	init_rst_menu();	
}



/*
*/
MENU_ITEM* get_first_item(void)
{
	return (MENU_ITEM*)&setup;
}



/*
*/
static void init_top_menu(void)
{
	//setup...test形成一个单向环形列表。
	setup.parent= NULL;
	setup.child= (MENU_ITEM*)&FIN;	//原值为F1.
	setup.sibble= (MENU_ITEM*)&cal;
	setup.up_sibble= (MENU_ITEM*)&rst;
	setup.f_key= key_Fn;
	
	init_ma_cal_menu();
	
	cal.parent= NULL;
	cal.child= (MENU_ITEM*)&CAL_In;
	cal.sibble= (MENU_ITEM*)&spoint;
	cal.up_sibble= (MENU_ITEM*)&setup;
	cal.f_key= key_Fn;
	
	spoint.parent= NULL;
	spoint.child= (MENU_ITEM*)&P1;
	spoint.sibble= (MENU_ITEM*)&hold;
	spoint.up_sibble= (MENU_ITEM*)&cal;
	spoint.f_key= key_Fn;
	
	hold.parent= NULL;
	hold.child= (MENU_ITEM*)&H1;
	hold.sibble= (MENU_ITEM*)&io_def;
	hold.up_sibble= (MENU_ITEM*)&spoint;
	hold.f_key= key_Fn;
	
	io_def.parent= NULL;
	io_def.child= (MENU_ITEM*)&IO_Out1;		//.child指向下一级菜单项，即下一级菜单项中的第1个。
	io_def.sibble= (MENU_ITEM*)&test_io;
	io_def.up_sibble= (MENU_ITEM*)&hold;
	io_def.f_key= key_Fn;

	test_io.parent= NULL;
	test_io.child= (MENU_ITEM*)&test_io_chilid;
	test_io.sibble= (MENU_ITEM*)&test;
	test_io.up_sibble= (MENU_ITEM*)&io_def;
	test_io.f_key= key_Fn;
	
	test.parent= NULL;
	test.child= (MENU_ITEM*)&test_chilid;
	test.sibble= (MENU_ITEM*)&rst;
	test.up_sibble= (MENU_ITEM*)&test_io;
	test.f_key= key_Fn;

	rst.parent= NULL;
	rst.child= (MENU_ITEM*)&rst_chilid;
	rst.sibble= (MENU_ITEM*)&setup;
	rst.up_sibble= (MENU_ITEM*)&test;
	rst.f_key= key_Fn;
}




/*
static MENU_ITEM F1={.content="F1"};
static MENU_ITEM F2={.content="F2"};
static MENU_ITEM F3={.content="F3"};
static MENU_ITEM F4={.content="F4"};
static MENU_ITEM F5={.content="F5"};
static MENU_ITEM F6={.content="F6"};
static MENU_ITEM F7={.content="F7"};
*/
static void init_Fn_menu(void)
{
	MENU_ITEM* parent;
	MENU_ITEM* head;
	MENU_ITEM* tail;
	
	parent= (MENU_ITEM*)&setup;
	
	//F1...F7形成一个单向环形列表。
//	CAL_In.parent= (MENU_ITEM*)&cal;
//	CAL_In.sibble= (MENU_ITEM*)&CAL_Pt;
//	CAL_In.f_key= leaf_Fn_cal_in;	//_lefa_Fn是叶子菜单项函数。	
	FIN.parent= parent;	
	FIN.sibble= (MENU_ITEM*)&F1;
	FIN.up_sibble= NULL;
	FIN.child= (MENU_ITEM*)&F1;		//FIN.sibble-> &F1, FIN.child -> &F1, 但是F1.parent是&setup，不是FIN。
	FIN.f_key= setup_in_leaf_Fn;
	FIN.f_enter= enter_Fn_setup_in;
	
	F1.parent= parent;	
	F1.sibble= (MENU_ITEM*)&F2;
	F1.up_sibble= (MENU_ITEM*)&F4;
	F1.child= (MENU_ITEM*)&F11;
	F1.f_key= key_Fn;
	
	F2.parent= parent;
	F2.sibble= (MENU_ITEM*)&F3;
	F2.up_sibble= (MENU_ITEM*)&F1;
	F2.child= (MENU_ITEM*)&F21;
	F2.f_key= key_Fn;
	
	F3.parent= parent;
	F3.sibble= (MENU_ITEM*)&F4;
	F3.up_sibble= (MENU_ITEM*)&F2;
	F3.child= (MENU_ITEM*)&F31;
	F3.f_key= key_Fn;
	
	F4.parent= parent;
	F4.sibble= (MENU_ITEM*)&F1;
	F4.up_sibble= (MENU_ITEM*)&F3;
	F4.child= (MENU_ITEM*)&F41;
	F4.f_key= key_Fn;	
//	
//	F5.parent= (MENU_ITEM*)&setup;
//	F5.sibble= (MENU_ITEM*)&F6;
//	
//	F6.parent= (MENU_ITEM*)&setup;
//	F6.sibble= (MENU_ITEM*)&F7;
//	
//	F7.parent= (MENU_ITEM*)&setup;
//	F7.sibble= (MENU_ITEM*)&F1;
}


void init_ma_cal_menu(void)
{
	MENU_ITEM* parent= (MENU_ITEM*)&setup;
	
	mA_Cal_4K.parent= parent;		//父级为空，则返回称重状态。
	mA_Cal_4K.child= NULL;
	mA_Cal_4K.sibble=(MENU_ITEM*) &mA_Cal_12K;
	mA_Cal_4K.up_sibble= NULL;
	mA_Cal_4K.f_key= leaf_Fn_ma_cal_4K;
	
	mA_Cal_12K.parent= parent;		//父级为空，则返回称重状态。
	mA_Cal_12K.child= NULL;
	mA_Cal_12K.sibble= (MENU_ITEM*) &mA_Cal_20K;
	mA_Cal_12K.up_sibble= NULL;
	mA_Cal_12K.f_key= leaf_Fn_ma_cal_12K;
	
	mA_Cal_20K.parent= parent;		//父级为空，则返回称重状态。
	mA_Cal_20K.child= NULL;
	mA_Cal_20K.sibble= (MENU_ITEM*) &mA_Cal_24K;
	mA_Cal_20K.up_sibble= NULL;
	mA_Cal_20K.f_key= leaf_Fn_ma_cal_20K;

	mA_Cal_24K.parent= parent;		//父级为空，则返回称重状态。
	mA_Cal_24K.child= NULL;
	mA_Cal_24K.sibble= (MENU_ITEM*) &mA_Cal_4K;
	mA_Cal_24K.up_sibble= NULL;
	mA_Cal_24K.f_key= leaf_Fn_ma_cal_24K;
	
	mA_Cal_12K.parent= parent;
	
}
/*
*/
void init_F1n_menu(void)
{
	//F1...F7形成一个单向环形列表。
	F11.parent= (MENU_ITEM*)&F1;
	F11.sibble= (MENU_ITEM*)&F12;
	F11.up_sibble= (MENU_ITEM*)&F17;
	F11.f_key= setup_F11_leaf_Fn;
	
	F12.parent= (MENU_ITEM*)&F1;
	F12.sibble= (MENU_ITEM*)&F13;
	F12.up_sibble= (MENU_ITEM*)&F11;
	F12.f_key= setup_F12_leaf_Fn;
	
	F13.parent= (MENU_ITEM*)&F1;
	F13.sibble= (MENU_ITEM*)&F14;
	F13.up_sibble= (MENU_ITEM*)&F12;
	F13.f_key= setup_F13_leaf_Fn;
	
	F14.parent= (MENU_ITEM*)&F1;
	F14.sibble= (MENU_ITEM*)&F15;
	F14.up_sibble= (MENU_ITEM*)&F13;
	F14.f_key= setup_F14_leaf_Fn;
	
	F15.parent= (MENU_ITEM*)&F1;
	F15.sibble= (MENU_ITEM*)&F16;
	F15.up_sibble= (MENU_ITEM*)&F14;
	F15.f_key= setup_F15_leaf_Fn;
	
	F16.parent= (MENU_ITEM*)&F1;
	F16.sibble= (MENU_ITEM*)&F17;
	F16.up_sibble= (MENU_ITEM*)&F15;
	F16.f_key= setup_F16_leaf_Fn;
	
	F17.parent= (MENU_ITEM*)&F1;
	F17.sibble= (MENU_ITEM*)&F11;
	F17.up_sibble= (MENU_ITEM*)&F16;
	F17.f_key= setup_F17_leaf_Fn;
}



/*
*/
void init_F2n_menu(void)
{
	F21.parent= (MENU_ITEM*)&F2;
	F21.sibble= (MENU_ITEM*)&F22;
	F21.up_sibble= (MENU_ITEM*)&F26;
	F21.f_key= setup_F21_leaf_Fn;
	
	F22.parent= (MENU_ITEM*)&F2;
	F22.sibble= (MENU_ITEM*)&F23;
	F22.up_sibble= (MENU_ITEM*)&F21;
	F22.f_key= setup_F22_leaf_Fn;
	
	F23.parent= (MENU_ITEM*)&F2;
	F23.sibble= (MENU_ITEM*)&F24;
	F23.up_sibble= (MENU_ITEM*)&F22;
	F23.f_key= setup_F23_leaf_Fn;
	
	F24.parent= (MENU_ITEM*)&F2;
	F24.sibble= (MENU_ITEM*)&F25;
	F24.up_sibble= (MENU_ITEM*)&F23;
	F24.f_key= setup_F24_leaf_Fn;
	
	F25.parent= (MENU_ITEM*)&F2;
	F25.sibble= (MENU_ITEM*)&F26;
	F25.up_sibble= (MENU_ITEM*)&F24;
	F25.f_key= setup_F25_leaf_Fn;
	
	F26.parent= (MENU_ITEM*)&F2;
	F26.sibble= (MENU_ITEM*)&F21;
	F26.up_sibble= (MENU_ITEM*)&F25;
	F26.f_key= setup_F26_leaf_Fn;
}



/*
*/
static void init_F3n_menu(void)
{
	//F31...F35形成一个单向环形列表。
	F31.parent= (MENU_ITEM*)&F3;
	F31.sibble= (MENU_ITEM*)&F32;
	F31.up_sibble= (MENU_ITEM*)&F35;
	F31.f_key= setup_F31_leaf_Fn;
	
	F32.parent= (MENU_ITEM*)&F3;
	F32.sibble= (MENU_ITEM*)&F33;
	F32.up_sibble= (MENU_ITEM*)&F31;
	F32.f_key= setup_F32_leaf_Fn;
	
	F33.parent= (MENU_ITEM*)&F3;
	F33.sibble= (MENU_ITEM*)&F34;
	F33.up_sibble= (MENU_ITEM*)&F32;
	F33.f_key= setup_F33_leaf_Fn;
	
	F34.parent= (MENU_ITEM*)&F3;
	F34.sibble= (MENU_ITEM*)&F35;
	F34.up_sibble= (MENU_ITEM*)&F33;
	F34.f_key= setup_F34_leaf_Fn;
	
	F35.parent= (MENU_ITEM*)&F3;
	F35.sibble= (MENU_ITEM*)&F31;
	F35.up_sibble= (MENU_ITEM*)&F31;
	F35.f_key= setup_F35_leaf_Fn;
}



/*
*/
static void init_F4n_menu(void)
{
	//F41...F42形成一个单向环形列表。
	F41.parent= (MENU_ITEM*)&F4;
	F41.sibble= (MENU_ITEM*)&F42;
	F41.up_sibble= (MENU_ITEM*)&F42;
	F41.child= NULL;			//
	F41.f_key= setup_F41_leaf_Fn;
	
	F42.parent= (MENU_ITEM*)&F4;
	F42.sibble= (MENU_ITEM*)&F41;
	F42.up_sibble= (MENU_ITEM*)&F41;
	F42.child= NULL;
	F42.f_key= setup_F42_leaf_Fn;
}



/*
static MENU_ITEM CAL_Pt={.content="Pt"};
static MENU_ITEM CAL_1d={.content="1d"};
static MENU_ITEM CAL_CP={.content="CP"};
static MENU_ITEM CAL_t={.content="t"};
static MENU_ITEM CAL_O={.content="O"};
static MENU_ITEM CAL_Load1={.content="Load1"};
static MENU_ITEM CAL_Load2={.content="Load2"};
static MENU_ITEM CAL_Load3={.content="Load3"};
static MENU_ITEM CAL_Load4={.content="Load4"};
static MENU_ITEM CAL_Sen={.content="Sen"};
static MENU_ITEM CAL_Siocal={.content="Siocal"};
static MENU_ITEM CAL_Pass={.content="Pass"};
*/
static void init_CALn_menu(void)
{
	MENU_ITEM* parent;
	MENU_ITEM* head;
	MENU_ITEM* tail;
	
	parent= (MENU_ITEM*)&cal;
	head= (MENU_ITEM*)&CAL_Pt;
	tail= (MENU_ITEM*)&CAL_SaP;
	
	
	//CAL_Pt->...CAL_Pass->是一个单向循环。
	CAL_In.parent= parent;
	CAL_In.sibble= (MENU_ITEM*)&CAL_Pt;
	CAL_In.f_key= leaf_Fn_cal_in;	//_lefa_Fn是叶子菜单项函数。
	
	CAL_Pt.parent= parent;
	CAL_Pt.sibble= (MENU_ITEM*)&CAL_1d;
	CAL_Pt.f_key= leaf_Fn_cal_pt;
	
	CAL_1d.parent= parent;
	CAL_1d.sibble= (MENU_ITEM*)&CAL_CP;
	CAL_1d.f_key= leaf_Fn_cal_1d;
	
	CAL_CP.parent= parent;
	CAL_CP.sibble= (MENU_ITEM*)&CAL_t;
	CAL_CP.f_key= leaf_Fn_cal_cp;
	
	CAL_t.parent= parent;
	CAL_t.sibble= (MENU_ITEM*)&CAL_Load1;
	CAL_t.f_key= leaf_Fn_cal_t;
	
	CAL_Load1.parent= parent;
	CAL_Load1.sibble= (MENU_ITEM*)&CAL_Load2;
	CAL_Load1.f_key= leaf_Fn_cal_load1;
	
	CAL_Load2.parent= parent;
	CAL_Load2.sibble= (MENU_ITEM*)&CAL_Load3;
	CAL_Load2.f_key= leaf_Fn_cal_load2;
	
	CAL_Load3.parent= parent;
	CAL_Load3.sibble= (MENU_ITEM*)&CAL_Load4;
	CAL_Load3.f_key= leaf_Fn_cal_load3;
	
	CAL_Load4.parent= parent;
	CAL_Load4.sibble= (MENU_ITEM*)&CAL_Siocal;
	CAL_Load4.f_key= leaf_Fn_cal_load4;
	
//	CAL_Sen.parent= (MENU_ITEM*)&cal;
//	CAL_Sen.sibble= (MENU_ITEM*)&CAL_Siocal;
//	CAL_Sen.f_key= key_Fn;
	
	CAL_Siocal.parent= parent;
	CAL_Siocal.sibble= (MENU_ITEM*)&CAL_Pass;
	CAL_Siocal.f_key= leaf_Fn_cal_siocal;
	
	CAL_Pass.parent= parent;
	CAL_Pass.sibble= (MENU_ITEM*)&CAL_RdP;
	CAL_Pass.f_key= leaf_Fn_cal_pass;
	
		
	//static MENU_ITEM CAL_RdP={.content="rd P  "};		//读取单线芯片的资料
	//static MENU_ITEM CAL_SaP={.content="SA P  "};		//保存单线芯片的资料
	
	CAL_RdP.parent= parent;
	CAL_RdP.sibble= (MENU_ITEM*)&CAL_SaP;
	CAL_RdP.f_key= leaf_Fn_cal_RdP;
	
	CAL_SaP.parent= parent;
	CAL_SaP.sibble= head;
	CAL_SaP.f_key= leaf_Fn_cal_SaP;
}



/*
*/
static void init_Pn_menu(void)
{
	//P1...P4形成一个单向环形列表。
	P1.parent= ( MENU_ITEM*)&spoint;
	P1.sibble= ( MENU_ITEM*)&P2;
	P1.up_sibble= ( MENU_ITEM*)&P4;
	P1.child= ( MENU_ITEM*)&P11;
	P1.f_key= key_Fn;
	
	P2.parent= ( MENU_ITEM*)&spoint;
	P2.sibble= ( MENU_ITEM*)&P3;
	P2.up_sibble= ( MENU_ITEM*)&P1;
	P2.child= ( MENU_ITEM*)&P21;
	P2.f_key= key_Fn;
	
	P3.parent= ( MENU_ITEM*)&spoint;
	P3.sibble= ( MENU_ITEM*)&P4;
	P3.up_sibble= ( MENU_ITEM*)&P2;
	P3.child= ( MENU_ITEM*)&P31;
	P3.f_key= key_Fn;
	
	P4.parent= ( MENU_ITEM*)&spoint;
	P4.sibble= ( MENU_ITEM*)&P1;
	P4.up_sibble= ( MENU_ITEM*)&P1;
	P4.child= ( MENU_ITEM*)&P41;
	P4.f_key= key_Fn;
	
	
	//配置子菜单
	init_P1n_menu();
	init_P2n_menu();
	init_P3n_menu();
	init_P4n_menu();
}



/*
*/
static void init_P1n_menu(void)
{
	//P11...P15形成一个单向环形列表。
	P11.parent= ( MENU_ITEM*)&P1;
	P11.sibble= ( MENU_ITEM*)&P12;
	P11.up_sibble= ( MENU_ITEM*)&P15;
	P11.f_key= leaf_Fn_spoint_P11;	
	
	P12.parent= ( MENU_ITEM*)&P1;
	P12.sibble= ( MENU_ITEM*)&P13;
	P12.up_sibble= ( MENU_ITEM*)&P11;
	P12.f_key= leaf_Fn_spoint_P12;	
	
	P13.parent= ( MENU_ITEM*)&P1;
	P13.sibble= ( MENU_ITEM*)&P14;
	P13.up_sibble= ( MENU_ITEM*)&P12;
	P13.f_key= leaf_Fn_spoint_P13;	
	
	P14.parent= ( MENU_ITEM*)&P1;
	P14.sibble= ( MENU_ITEM*)&P15;
	P14.up_sibble= ( MENU_ITEM*)&P13;
	P14.f_key= leaf_Fn_spoint_P14;	
	
	P15.parent= ( MENU_ITEM*)&P1;
	P15.sibble= ( MENU_ITEM*)&P11;
	P15.up_sibble= ( MENU_ITEM*)&P14;
	P15.f_key= leaf_Fn_spoint_P15;	
}



/*
*/
static void init_P2n_menu(void)
{
	//P21...P25形成一个单向环形列表。
	P21.parent= ( MENU_ITEM*)&P2;
	P21.sibble= ( MENU_ITEM*)&P22;
	P21.up_sibble= ( MENU_ITEM*)&P25;
	P21.f_key= leaf_Fn_spoint_P11;	
	
	P22.parent= ( MENU_ITEM*)&P2;
	P22.sibble= ( MENU_ITEM*)&P23;
	P22.up_sibble= ( MENU_ITEM*)&P21;
	P22.f_key= leaf_Fn_spoint_P12;	
	
	P23.parent= ( MENU_ITEM*)&P2;
	P23.sibble= ( MENU_ITEM*)&P24;
	P23.up_sibble= ( MENU_ITEM*)&P22;
	P23.f_key= leaf_Fn_spoint_P13;	
	
	P24.parent= ( MENU_ITEM*)&P2;
	P24.sibble= ( MENU_ITEM*)&P25;
	P24.up_sibble= ( MENU_ITEM*)&P23;
	P24.f_key= leaf_Fn_spoint_P14;	
	
	P25.parent= ( MENU_ITEM*)&P2;
	P25.sibble= ( MENU_ITEM*)&P21;
	P25.up_sibble= ( MENU_ITEM*)&P24;
	P25.f_key= leaf_Fn_spoint_P15;	
}



/*
*/
static void init_P3n_menu(void)
{
	//P31...P35形成一个单向环形列表。
	P31.parent= ( MENU_ITEM*)&P3;
	P31.sibble= ( MENU_ITEM*)&P32;
	P31.up_sibble= ( MENU_ITEM*)&P35;
	P31.f_key= leaf_Fn_spoint_P11;	
	
	P32.parent= ( MENU_ITEM*)&P3;
	P32.sibble= ( MENU_ITEM*)&P33;
	P32.up_sibble= ( MENU_ITEM*)&P31;
	P32.f_key= leaf_Fn_spoint_P12;	
	
	P33.parent= ( MENU_ITEM*)&P3;
	P33.sibble= ( MENU_ITEM*)&P34;
	P33.up_sibble= ( MENU_ITEM*)&P32;
	P33.f_key= leaf_Fn_spoint_P13;	
	
	P34.parent= ( MENU_ITEM*)&P3;
	P34.sibble= ( MENU_ITEM*)&P35;
	P34.up_sibble= ( MENU_ITEM*)&P33;
	P34.f_key= leaf_Fn_spoint_P14;	
	
	P35.parent= ( MENU_ITEM*)&P3;
	P35.sibble= ( MENU_ITEM*)&P31;
	P35.up_sibble= ( MENU_ITEM*)&P34;
	P35.f_key= leaf_Fn_spoint_P15;	
}

static void init_P4n_menu(void)
{
	//P41...P45形成一个单向环形列表。
	P41.parent= ( MENU_ITEM*)&P4;
	P41.sibble= ( MENU_ITEM*)&P42;
	P41.up_sibble= ( MENU_ITEM*)&P45;
	P41.f_key= leaf_Fn_spoint_P11;	
	
	P42.parent= ( MENU_ITEM*)&P4;
	P42.sibble= ( MENU_ITEM*)&P43;
	P42.up_sibble= ( MENU_ITEM*)&P41;
	P42.f_key= leaf_Fn_spoint_P12;	
	
	P43.parent= ( MENU_ITEM*)&P4;
	P43.sibble= ( MENU_ITEM*)&P44;
	P43.up_sibble= ( MENU_ITEM*)&P42;
	P43.f_key= leaf_Fn_spoint_P13;	
	
	P44.parent= ( MENU_ITEM*)&P4;
	P44.sibble= ( MENU_ITEM*)&P45;
	P44.up_sibble= ( MENU_ITEM*)&P43;
	P44.f_key= leaf_Fn_spoint_P14;	
	
	P45.parent= ( MENU_ITEM*)&P4;
	P45.sibble= ( MENU_ITEM*)&P41;
	P45.up_sibble= ( MENU_ITEM*)&P44;
	P45.f_key= leaf_Fn_spoint_P15;	
}



/*
*/
static void init_Hn_menu(void)
{
	H1.parent= ( MENU_ITEM*)&hold;
	H1.sibble= ( MENU_ITEM*)&H2;
	H1.up_sibble= ( MENU_ITEM*)&H3;
	H1.f_key= leaf_Fn_hold_H1;
	
	H2.parent= ( MENU_ITEM*)&hold;
	H2.sibble= ( MENU_ITEM*)&H3;
	H2.up_sibble= ( MENU_ITEM*)&H1;
	H2.f_key= leaf_Fn_hold_H2;
	
	H3.parent= ( MENU_ITEM*)&hold;
	H3.sibble= ( MENU_ITEM*)&H1;
	H3.up_sibble= ( MENU_ITEM*)&H2;
	H3.f_key= leaf_Fn_hold_H3;
}



/*
*/
static void init_IOn_menu(void)
{
	IO_Out1.parent= ( MENU_ITEM*)&io_def;
	IO_Out1.sibble= ( MENU_ITEM*)&IO_Out2;
	IO_Out1.up_sibble= ( MENU_ITEM*)&IO_In1;
	IO_Out1.f_key= leaf_Fn_io_out1;
	
	IO_Out2.parent= ( MENU_ITEM*)&io_def;
	IO_Out2.sibble= ( MENU_ITEM*)&IO_In1;
	IO_Out2.up_sibble= ( MENU_ITEM*)&IO_Out1;
	IO_Out2.f_key= leaf_Fn_io_out2;
	
	IO_In1.parent= ( MENU_ITEM*)&io_def;
	IO_In1.sibble= ( MENU_ITEM*)&IO_Out1;
	IO_In1.up_sibble= ( MENU_ITEM*)&IO_Out2;
	IO_In1.f_key= leaf_Fn_io_in1;
}



/*
*/
static void init_test_io_menu(void)
{
	test_io_chilid.parent= ( MENU_ITEM*)&test_io; 
	test_io_chilid.sibble= NULL;
	test_io_chilid.up_sibble= NULL;
	test_io_chilid.f_key= leaf_Fn_test_io_child;
	test_io_chilid.f_enter=  enter_Fn_test_io;
}



/*
*/
static void init_test_menu(void)
{
	test_chilid.parent= (MENU_ITEM*)&test;
	test_chilid.sibble= NULL;
	test_chilid.up_sibble= NULL;
	test_chilid.f_key= leaf_Fn_test_child;
}



/*
*/
static void init_rst_menu(void)
{
	rst_chilid.f_key= leaf_Fn_rst;
	rst_chilid.parent= (MENU_ITEM*)&rst;
}



//!!定义各个菜单项的回调函数。
/*适用于所有的菜单项切换，
*/
void key_Fn(MSG_U msg)
{
	uint16_t key;
	
	if(MSG_TYPE_KEY == msg.type){
		key= msg.key;
			
		if(KEY_K3_MODE == key){
			//在同级菜单循环切换。
			cur_item= cur_item->sibble;	
			seg_updata(cur_item->content);
			
			uartS("\nsibble");
		}
		else if(KEY_K2_OPT == key){
			//在同级菜单循环切换。
			if(cur_item->up_sibble){
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
				
				uartS("\nup_sibble");
			}
			
		}
		else if(KEY_K1_ESC == key){	
			//返回上级菜单
			if(cur_item->parent){
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);	
			}
			else{
				uartS("\nerr:no parent");
			}
		}
		else if(KEY_K4_ENTER == key){
			//进入子菜单。
			if(cur_item->child){
				cur_item= cur_item->child;	
				seg_updata(cur_item->content);
				
				if(cur_item->f_enter)
					cur_item->f_enter();
			}
			else{
				uartS("\nerr:no child");
			}
		}
		else if(KCODE_K2_K3 == key){
			//键OPT、MODE同时按下。
			if(1 == cur_item->id){
				//是SETUP菜单。
				cur_item= (MENU_ITEM*) &mA_Cal_4K;
				seg_updata(cur_item->content);
				
				if(cur_item->f_enter)
					cur_item->f_enter();
			}
		}
		else{ 
			//无效按键：KEY_IN_L或KEY_IN_H。
		}
	}
}



//!!定义各个菜单项的回调函数。
/*适用于所有的菜单项切换，
*/
void key_F1_4(MSG_U msg)
{
	uint16_t key;
	
	if(MSG_TYPE_KEY == msg.type){
		key= msg.key;
			
		if(KEY_K3_MODE == key){
			//在同级菜单循环切换。
			cur_item= cur_item->sibble;	
			seg_updata(cur_item->content);
		}
		else if(KEY_K2_OPT == key){
			//在同级菜单循环切换。
			if(cur_item->up_sibble){
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
		}
		else if(KEY_K1_ESC == key){	
			//返回上级菜单
			if(cur_item->parent){
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);	
			}
			else{
				uartS("\nerr:no parent");
			}
		}
		else if(KEY_K4_ENTER == key){
			//进入子菜单。
			if(cur_item->child){
				cur_item= cur_item->child;	
				seg_updata(cur_item->content);
				set_one_seg_point(2, 1);	//无它，在F11变为F1.1。
			}
			else{
				uartS("\nerr:no child");
			}
		}
		else{
			//无效按键：KEY_IN_L或KEY_IN_H。
		}
	}
}



/*
*/
void leaf_Fn_ma_cal_4K(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 6;	//有效范围：1~6。左起第1个为1。
	
	static uint16_t val_change;
	uint16_t key;
	char tmp8[8];				//共8B，包含第1个' '（灯状态）和UI的6个字符和1个'\0'。
	char str[48];
	
	
	if(MSG_TYPE_KEY == msg.type){
		key= msg.key;

		switch (sta){
			case 0:	//显示着"i 4000"。
				if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);
				}
				else if(KEY_K4_ENTER == key){
					//调整
					show_val(para_self.da4K , tmp8);
					seg_updata(tmp8);
					val_change= para_self.da4K;
					
					flag_ma_cal= 1;
					osDelay(100);
					dac_out(val_change*16);
					
					sta= 1;
					idx_seg= 4;
					set_one_seg_flash(idx_seg, SEG_FLASH);
				}
				else if(KEY_K1_ESC == key){	
					sprintf(str, "sfsfd");
					uartS(str);
					
					//返回上级菜单
					if(cur_item->parent){
						cur_item= cur_item->parent;	
						seg_updata(cur_item->content);	
					}
					else{
						uartS("\nerr:no parent");
					}
					
					flag_ma_cal= 0;
					seg_flash_all(0);
				}
				
				break;
			
			case 1:	//显示着4.000mA对应的DA值，通过MODE键调小，OPT键调大，ENTER键盘保存，ESC键返回sta 0并显示"i 4000"。			
				if(KEY_K1_ESC == key){
					//返回状态0。
					seg_updata("i 4000");
					
					flag_ma_cal= 0;
					sta= 0;
					seg_flash_all(0);
				}
				else if(key == KEY_K2_OPT){
					if(ANA_V_DEF == para_self.ana_out_mode){
						inc_one_seg(idx_seg);
					}
					else
						inc_one_seg(idx_seg);
					
					//将当前显示值拷贝到tmp8[1~6]。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					if(4095< x)
						x= 4095;
					
					//设置7760的DA值。
					dac_out(x*16);	
				}
				else if(key == KEY_K3_MODE){
					set_one_seg_flash(idx_seg, SEG_LIGHT);
					
					idx_seg++;
					if(6< idx_seg)
						idx_seg= 1;
					set_one_seg_flash(idx_seg, SEG_FLASH);
					
					//将当前显示值拷贝到tmp8[1~6]。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					if(4095< x)
						x= 4095;
					
					//设置7760的DA值。
					dac_out(x*16);	
				}	
				else if(KEY_K4_ENTER == key){
					//保存调整值到FLASH参数区。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					if(4095< x)
						x= 4095;
									
					uint16_t tmp16= para_self.da4K;
					para_self.da4K= (uint16_t)x;
					
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
						uartS("\nsave para_self.da4K");
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);
						
						
						flag_ma_cal= 0;
						sta= 0;
						seg_flash_all(0);
					}
					else{		
						para_self.da4K= tmp16;		//保存失败，恢复旧值（断电完蛋）。
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save para_self.da4K");
						osDelay(1000);
					}
				}
				else{
				}
				
				break;
			
			default:
				break;
		}
	}
}



void leaf_Fn_ma_cal_12K(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6。左起第1个为1。	
	static uint16_t val_change;
	uint16_t key;
	char tmp8[8];				//共8B，包含第1个' '（灯状态）和UI的6个字符和1个'\0'。
	
	
	
	if(MSG_TYPE_KEY == msg.type){
		key= msg.key;
		
		switch (sta){
			case 0:	//显示着"i12000"。
				if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);
				}
				else if(KEY_K4_ENTER == key){
					//调整
					show_val(para_self.da12K , tmp8);
					seg_updata(tmp8);
					val_change= para_self.da12K;
					
					flag_ma_cal= 1;
					osDelay(100);
					dac_out(val_change*16);
					
					sta= 1;
					idx_seg= 3;
					set_one_seg_flash(idx_seg, SEG_FLASH);
				}
				else if(KEY_K1_ESC == key){	
					//返回上级菜单
					if(cur_item->parent){
						cur_item= cur_item->parent;	
						seg_updata(cur_item->content);	
					}
					else{
						uartS("\nerr:no parent");
					}
					
					flag_ma_cal= 0;
					seg_flash_all(0);
				}
				break;
			
			case 1:	//显示着4.000mA对应的DA值，通过MODE键调小，OPT键调大，ENTER键盘保存，ESC键返回sta 0并显示"i 4000"。
				if(KEY_K1_ESC == key){
					//返回状态0。
					seg_updata("i12000");
					
					flag_ma_cal= 0;
					sta= 0;
					seg_flash_all(0);
				}
				else if(key == KEY_K2_OPT){
					if(ANA_V_DEF == para_self.ana_out_mode){
						inc_one_seg(idx_seg);
					}
					else
						inc_one_seg(idx_seg);
					
					//将当前显示值拷贝到tmp8[1~6]。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					if(4095< x)
						x= 4095;
					
					//设置7760的DA值。
					dac_out(x*16);	
				}
				else if(key == KEY_K3_MODE){
					set_one_seg_flash(idx_seg, SEG_LIGHT);
					
					idx_seg++;
					if(6< idx_seg)
						idx_seg= 1;
					set_one_seg_flash(idx_seg, SEG_FLASH);
					
					//将当前显示值拷贝到tmp8[1~6]。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					if(4095< x)
						x= 4095;
					
					//设置7760的DA值。
					dac_out(x*16);	
				}		
				else if(KEY_K4_ENTER == key){
					//保存调整值到FLASH参数区。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					if(4095< x)
						x= 4095;
					
					uint16_t tmp16= para_self.da12K;
					para_self.da12K= (uint16_t)x;
					
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
						uartS("\nsave para_self.da12K");
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);
						
						
						flag_ma_cal= 0;
						sta= 0;
						seg_flash_all(0);
					}
					else{		
						para_self.da12K= tmp16;		//保存失败，恢复旧值（断电完蛋）。
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save para_self.da12K");
						osDelay(1000);
					}
				}
				else{
				}
				break;
			
			default:
				break;
		}
	}
}



void leaf_Fn_ma_cal_20K(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6。左起第1个为1。
	static uint16_t val_change;
	uint16_t key;
	char tmp8[8];				//共8B，包含第1个' '（灯状态）和UI的6个字符和1个'\0'。
	
	
	
	if(MSG_TYPE_KEY == msg.type){
		key= msg.key;
		
		switch (sta){
			case 0:	//显示着"i 4000"。
				if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);
				}
				else if(KEY_K4_ENTER == key){
					//调整
					show_val(para_self.da20K , tmp8);
					seg_updata(tmp8);
					val_change= para_self.da20K;
					
					flag_ma_cal= 1;
					osDelay(100);
					dac_out(val_change*16);
					
					sta= 1;
					idx_seg= 3;
					set_one_seg_flash(idx_seg, SEG_FLASH);
				}
				else if(KEY_K1_ESC == key){	
					//返回上级菜单
					if(cur_item->parent){
						cur_item= cur_item->parent;	
						seg_updata(cur_item->content);	
					}
					else{
						uartS("\nerr:no parent");
					}
					
					flag_ma_cal= 0;
					seg_flash_all(0);
				}
				break;
			
			case 1:	//显示着4.000mA对应的DA值，通过MODE键调小，OPT键调大，ENTER键盘保存，ESC键返回sta 0并显示"i 4000"。
				if(KEY_K1_ESC == key){
					//返回状态0。
					seg_updata("i20000");
					
					flag_ma_cal= 0;
					sta= 0;
					seg_flash_all(0);
				}
				else if(key == KEY_K2_OPT){
					if(ANA_V_DEF == para_self.ana_out_mode){
						inc_one_seg(idx_seg);
					}
					else
						inc_one_seg(idx_seg);
					
					//将当前显示值拷贝到tmp8[1~6]。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					if(4095< x)
						x= 4095;
					
					//设置7760的DA值。
					dac_out(x*16);	
				}
				else if(key == KEY_K3_MODE){
					set_one_seg_flash(idx_seg, SEG_LIGHT);
					
					idx_seg++;
					if(6< idx_seg)
						idx_seg= 1;
					set_one_seg_flash(idx_seg, SEG_FLASH);
					
					//将当前显示值拷贝到tmp8[1~6]。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					if(4095< x)
						x= 4095;
					
					//设置7760的DA值。
					dac_out(x*16);	
				}	
				else if(KEY_K4_ENTER == key){
					//保存调整值到FLASH参数区。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					if(4095< x)
						x= 4095;
					
					uint16_t tmp16= para_self.da20K;
					para_self.da20K= (uint16_t)x;
					
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
						uartS("\nsave para_self.da20K");
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);
						
						
						flag_ma_cal= 0;
						sta= 0;
						seg_flash_all(0);
					}
					else{		
						para_self.da20K= tmp16;		//保存失败，恢复旧值（断电完蛋）。
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save para_self.da20K");
						osDelay(1000);
					}
				}
				else{	
					
				}
				break;
			
			default:
				break;
		}
	}
}



/*先显示i24.000，再修改为实际值。修改时，按OPT键移动光标，按MODE键修改值，按ENTER键保存，ESC键返回。
*/
void leaf_Fn_ma_cal_24K(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6。左起第1个为1。
	static uint16_t val_change;
	uint16_t key;
	char tmp8[8];				//共8B，包含第1个' '（灯状态）和UI的6个字符和1个'\0'。	
	
	
	//输出最大值
	dac_out(4095*16);
	
	if(MSG_TYPE_KEY == msg.type){
		key= msg.key;
		
		switch (sta){
			case 0:	//显示着"i24000"。
				if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);
				}
				else if(KEY_K4_ENTER == key){
					//调整
					show_val(para_self.mA24K , tmp8);
					seg_updata(tmp8);
					set_one_seg_point(3, 1);
					
					val_change= para_self.mA24K;
					
					flag_ma_cal= 1;
					osDelay(100);
					dac_out(4095*16);
					
					sta= 1;
				}
				else if(KEY_K1_ESC == key){	
					//返回上级菜单
					if(cur_item->parent){
						cur_item= cur_item->parent;	
						seg_updata(cur_item->content);	
					}
					else{
						uartS("\nerr:no parent");
					}
					
					sta= 0;
					seg_flash_all(0);
				}
				break;
			
			case 1:	//显示着实际的电流输出最大值：24.000对应的DA值，通过MODE键调大，OPT键调小，ENTER键盘保存，ESC键返回sta 0并显示"i24000"。
				if(KEY_K1_ESC == key){
					//返回状态0。
					seg_updata("i24000");
					set_one_seg_point(3, 1);
					
					sta= 0;
					seg_flash_all(0);
				}
				else if(key == KEY_K2_OPT){
					if(ANA_V_DEF == para_self.ana_out_mode){
						inc_one_seg(idx_seg);
					}
					else
						inc_one_seg(idx_seg);
				}
				else if(key == KEY_K3_MODE){
					set_one_seg_flash(idx_seg, SEG_LIGHT);
					
					idx_seg++;
					if(6< idx_seg)
						idx_seg= 1;
					set_one_seg_flash(idx_seg, SEG_FLASH);
				}
				else if(KEY_K4_ENTER == key){
					//保存调整值到FLASH参数区。
					//将当前显示值拷贝到tmp8[1~6]。
					seg_copy_to_tmp(tmp8);		
					tmp8[0]= ' ';
					tmp8[7]= '\0';
					int32_t x= atoi(tmp8);
					
					
					uint16_t tmp16= para_self.mA24K;
					para_self.mA24K= (uint16_t)x;
					
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
						uartS("\nsave para_self.mA24K");
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);

						sta= 0;
						seg_flash_all(0);
					}
					else{		
						para_self.da4K= tmp16;		//保存失败，恢复旧值（断电完蛋）。
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save para_self.mA24K");
						osDelay(1000);
					}
				}
				else{
				}
				break;
			
			default:
				break;
		}
	}
}



/*test_io的叶子菜单项处理函数。
!!轮询In1的状态。
*/
void leaf_Fn_test_io_child(MSG_U msg)
{
	static uint8_t sta_out1=1, sta_out2=1;	//因为进入菜单时，显示"FF"，对应的sta_out1,_out2应为1。（即输出高，灯不亮）。

	
	if(MSG_TYPE_KEY  == msg.type){
		uint16_t key;
		key= msg.key;
		
		if(KEY_K1_ESC == key){
			cur_item= cur_item->parent;
			seg_updata(cur_item->content);
			
			para_coil&= ~COIL_BIT_MASK_TEST_SW;
		}
		else if(KEY_K2_OPT == key){		//切换OUT1的状态
			if(sta_out1){
				//OUT1输出L，
				
				sta_out1= 0;
				
				//更新显示内容。
				set_one_seg(5, 'o', 0);	
				OUT1_VALID;		//'o'表示有效。
			}
			else{
				//OUT1输出H。
				
				sta_out1= 1;
				
				//更新显示内容。
				set_one_seg(5, 'F', 0);
				OUT1_INVALID;	//'F'表示无效。
			}	
		}
		else if(KEY_K3_MODE == key){	//切换OUT2的状态
			if(sta_out2){
				//OUT2输出L，
				
				sta_out2= 0;
				
				//更新显示内容。
				set_one_seg(6, 'o', 0);
				OUT2_VALID;		//'o'表示有效。
			}
			else{
				//OUT2输出H。
				
				sta_out2= 1;
				
				//更新显示内容。
				set_one_seg(6, 'F', 0);
				OUT2_INVALID;	//'F'表示无效。
			}
		}
		else if(KEY_IN1_INVALID == key){
			set_one_seg(1, 'F', 0);		//无效
		}
		else if(KEY_IN1_VALID == key){
			set_one_seg(1, 'o', 0);		//有效	
		}
	}
}



/*test的叶子菜单项处理函数。
*/
void leaf_Fn_test_child(MSG_U msg)
{
	static uint8_t i= 0;	//i=0:显示888，i=1：显示版本，i=2：显示编号。
	static uint8_t isFlash= 0;
	uint16_t key;
	char str[7];			//对应6位数码管，含字符串尾'\0'，共7个字符。
	
	if(MSG_TYPE_KEY == msg.type){
		key= msg.key;
		
		if(KEY_K1_ESC == key){
			cur_item= cur_item->parent;
			seg_updata(cur_item->content);
			
			
			i= 0;
			seg_flash(0);
		}
		else if(KEY_K4_ENTER == key){
			//闪
			if(0 == i){//只有“888888”时才闪。
				seg_flash(isFlash);
				isFlash= !isFlash;
				set_one_seg_point(1,1);
				set_one_seg_point(2,1);
				set_one_seg_point(3,1);
				set_one_seg_point(4,1);
				set_one_seg_point(5,1);
				set_one_seg_point(6,1);
			}
				
		}
		else if(KEY_K3_MODE == key){
			seg_flash(0);
			
			i++;
			i%=3;
			
			//显示版本（HW，SW）、编号和“888888”之间切换。
			if(0 == i){
				seg_updata("8888888");	//测试序列：888888
				set_one_seg_point(1,1);
				set_one_seg_point(2,1);
				set_one_seg_point(3,1);
				set_one_seg_point(4,1);
				set_one_seg_point(5,1);
				set_one_seg_point(6,1);
			}
			else if(1 == i){
				str[0]= str_ver[12];	//'V'
				str[1]= str_ver[13];	//y
				str[2]= str_ver[15];	//mm
				str[3]= str_ver[16];	
				str[4]= str_ver[18];	//dd
				str[5]= str_ver[19];
				str[6]= '\0';
				
				seg_updata(str);	//版本号
				//Uy.mm.dd
				set_one_seg_point(2,1);
				set_one_seg_point(4,1);
			}
			else{
				char str[7];			
				if(999999< para_self.sn)
					strcpy(str, "000000");
				else
					sprintf(str, "%d", para_self.sn);
				
				seg_updata(str);	//编号
			}  
			
			
		}
		else if(KEY_K2_OPT == key)
		{
			//无效按键。
		}
	}
}


/*进入校准流程的叶子菜单项处理函数。即完成密码验证。
*/
void leaf_Fn_cal_in(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static uint8_t cnt_pass_err= 0;	//密码错误次数，但4次时锁定（只能关电）。
	static char tmp6[7];		//有效范围：1~6.	
	uint16_t key;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				sta= 1;
				seg_updata("000000");	//测试序列：PASS
				//第1个‘0’闪
				idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			cnt_pass_err=0;
			
			break;
		case 1:
			//输入密码：按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
			if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);	
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				
				seg_copy_to_tmp(tmp6);
				//比较密码，如果正确，进入下一个邻居菜单。
				if(0UL == pass_compare(tmp6)){
					sta= 0;
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	//cur_item->f_enter();
					
					set_one_seg_flash(idx_seg, SEG_LIGHT);	//关闭闪烁
				}
				else{
					cnt_pass_err++;
					//否则，显示Error为1秒。
					seg_copy_to_tmp(tmp6);
					set_one_seg_flash(idx_seg, SEG_LIGHT);	//关闭闪烁
					
					if(1 == cnt_pass_err)
						seg_updata("Error1");
					else if(2 == cnt_pass_err)
						seg_updata("Error2");
					else if(3 == cnt_pass_err)
						seg_updata("Error3");
					else if(4 == cnt_pass_err){
						seg_updata("Error4");
						while(1);
					}
					osDelay(2000);
					seg_updata("000000");
					
					idx_seg= 1;
					set_one_seg_flash(idx_seg, SEG_FLASH);
				}
			}
			else{
				//不处理
			}
			
			break;
		default:
			break;
	}
	

}	

/*小数点位置叶子菜单项处理函数。
带有状态的（sta）。
从pt开始，经1d,cp,t,load1器件不能退出，之后的load2,load3,load4,sen,siocal和pass可以退出。
*/
void leaf_Fn_cal_pt(MSG_U msg)
{
	static uint8_t sta= 0;
//	static uint8_t idx_seg= 1;	//有效范围：1~6
	static  uint8_t pos;		//小数点位置。
	char tmp8[8];
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:	
			if(KEY_K4_ENTER == key){
				//读取当前小数点，并显示。
				pos= para_xxx.pos_dot;
				
				show_pt(pos, tmp8);
				seg_updata(tmp8);
				
				set_one_seg_point(6-pos, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
				
				sta= 1;
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT键调整数值，按Enter确认并进入同级下一个菜单。
			if(key == KEY_K2_OPT){
				pos++;
				pos%=5;	//0,1,2,3,4.
				
				//重新显示小数点位置。
				show_pt(pos, tmp8);
				seg_updata(tmp8);
				
				set_one_seg_point(6-pos, 1);
			}
			else if(KEY_K3_MODE == key){
				if(0 == pos)
					pos= 4;
				else
					pos--;

				pos%=5;	//0,1,2,3,4.
				
				//重新显示小数点位置。
				show_pt(pos, tmp8);
				seg_updata(tmp8);
				
				set_one_seg_point(6-pos, 1);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.pos_dot;
				para_xxx.pos_dot= pos;
				
								
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.pos_dot");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{		
					para_xxx.pos_dot= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.pos_dot");
					osDelay(1000);
				}
			}
			
			break;
		
		default:
			break;
	}		
}



/*最大量程叶子菜单项处理函数。
!!按当前的pt值显示。
*/
void leaf_Fn_cal_cp(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	char tmp8[8];				//
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:	
			if(KEY_K4_ENTER == key){
				//进入最大量程设置，并显示“100000”。!!不读取当前量程。
				seg_updata("000000 ");
				set_one_seg_flash(1, SEG_FLASH);
				set_one_seg_point(6-para_xxx.pos_dot, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
				
				sta= 1;
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
			
		case 1:
			//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
			if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.fs_max_hi;
				uint16_t val_tmp16_2= para_xxx.fs_max_lo;
				
				seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8[1~6]。
				tmp8[0]= ' ';
				tmp8[7]= '\0';
				uint32_t cp= atoi(tmp8);
				para_xxx.fs_max_hi= cp>> 16;
				para_xxx.fs_max_lo= (uint16_t)cp;
				
								
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.fs_max_hi/lo");
					
					update_fs_max();		//更新二次参数。
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{	
					val_tmp16= para_xxx.fs_max_hi= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					val_tmp16_2= para_xxx.fs_max_lo= val_tmp16_2;	
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.fs_max_hi/lo");
					osDelay(1000);
				}
			}
			
			break;
		
		default:
			break;
	}			
}



/*零点叶子菜单项处理函数。
!!显示当前的mv值。（第1个数码管显示t，不可被覆盖）。
在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
从pt开始，经1d,cp,t,load1器件不能退出，之后的load2,load3,load4,sen,siocal和pass可以退出。
*/
void leaf_Fn_cal_t(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t disp_mv= 0;	//是否显示mv值。
	static int32_t ad;			//和uV伴随而来的ad值。
	uint16_t key;
	char tmp8[8];
	
	if(msg.type == MSG_TYPE_KEY){
		key= msg.key;
		
		switch (sta){
			case 0:	
				if(KEY_K4_ENTER == key){
					disp_mv= 1;	//按Enter键，以允许显示mv值。
					mode_mv_wt= MODE_MV;
					
					sta= 1;
					
					//准备调整校准过程中的滤波强度。
					flag_para_update_fir= 'C';
				}
				else if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	
				}
				else if(KEY_K1_ESC == key){
					//返回上一级菜单。
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);
				}
				
				break;
				
			case 1:
				//按Enter确认并进入同级下一个菜单。
				if(key == KEY_K4_ENTER){
					
					//需要判断当前STAB为1才能保存，否则什么也不做。
					if(seg_stab_sta()){
						//保存旧值。
						POINT pt;
						pt.load= point[0].load;
						pt.ad= point[0].ad;
						pt.used= point[0].used;
						
						seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
						
						tmp8[0]= ' ';
						if('C' == tmp8[1])
							tmp8[1]= ' ';			//去掉第1个数码管的'C'。
						tmp8[7]='\0';
						point[0].load= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
						point[0].ad= ad;
						point[0].used= 1;
						
						point[1].used= 0;
						point[2].used= 0;
						point[3].used= 0;
						point[4].used= 0;
						
										
						if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
							uartS("\nsave load 0");
						
							set_one_seg(1,'o',0);		//按确认后，需要第1个数码管显示'o'。
							disp_mv= 0;					//停止动态显示
						
							sta= 2;							
						}
						else{		
							point[0].load= pt.load;		//保存失败，恢复旧值（断电完蛋）。
							point[0].ad= pt.ad;
							point[0].used= pt.used;
							
							seg_flash_all(0);
							seg_updata("Err00F");
							
							uartS("\nerr save load 0");
							osDelay(1000);
						}
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//准备恢复校准过程中的滤波强度。
					flag_para_update_fir= 'X';
				}
				
				break;
				
			case 2:
				//按Enter确认并进入同级下一个菜单。
				if(key == KEY_K4_ENTER){						
					//切换到下一个菜单项。
					cur_item= cur_item->sibble;
					seg_updata(cur_item->content);
						
					sta= 0;
					disp_mv= 0;
					
					//准备恢复校准过程中的滤波强度。
					flag_para_update_fir= 'X';
				}

				
				break;
			
			default:
				break;
		}
	}
	else if(msg.type == MSG_TYPE_MV_WT){
		uartS("\nmv");
		if(disp_mv){
			//显示mv值。
			seg_mv_to_seg(msg.uv, msg.dat[0]);
			set_one_seg(1,'t',0);
			
			ad= msg.ad;
		}	
	}
}



/*标定第1点叶子菜单项处理函数。
先显示LoAD1，确定后显示"Add ld"约1秒后，显示mv值。再确定，如果此时STAB有效，则进入设置标定1的称重值；无效（不稳）则死等。QQ如何退出死等状态？
在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
*/
void leaf_Fn_cal_load1(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_flash= 1;	//有效范围：1~6
	static uint8_t disp_mv= 0;		//是否显示mv值。
	static int32_t ad;				//和uV伴随而来的ad值。
	uint16_t key;
	char tmp8[8];
	
	
	if(msg.type == MSG_TYPE_KEY){
		key= msg.key;
		
		switch (sta){
			case 0:	
				if(KEY_K4_ENTER == key){
					seg_updata("Add ld ");
					osDelay(1000);
					
					disp_mv=1;
					mode_mv_wt= MODE_MV;
					
					sta= 1;
					
					//准备调整校准过程中的滤波强度。
					flag_para_update_fir= 'C';
				}
				else if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	
				}
				else if(KEY_K1_ESC == key){
					//返回上一级菜单。
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);
				}
		
				break;
				
			case 1:
				if(key == KEY_K4_ENTER){
					
					//需要判断当前STAB为1才能保存，否则什么也不做。
					if(seg_stab_sta()){
						disp_mv= 0;	//停止动态显示
						
						//保存当前mv值。
						seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
					
						tmp8[0]= ' ';
						if('C' == tmp8[1])
							tmp8[1]= ' ';			//去掉第1个数码管的'C'。
						tmp8[7]='\0';
						point[1].uv= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
						
					
						//
						seg_updata("000000 ");
						idx_flash= 1;
						set_one_seg_flash(idx_flash, SEG_FLASH);
						set_one_seg_point(6-para_xxx.pos_dot, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
						
						sta= 2;
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//滤波强度要恢复。
					flag_para_update_fir= 'X';
				}
				
				break;
				
			case 2:
				//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
				if(key == KEY_K2_OPT){
					inc_one_seg(idx_flash);
				}
				else if(key == KEY_K3_MODE){
					set_one_seg_flash(idx_flash, SEG_LIGHT);
					
					idx_flash++;
					if(6< idx_flash)
						idx_flash= 1;
					set_one_seg_flash(idx_flash, SEG_FLASH);
				}
				else if(key == KEY_K4_ENTER){
					//保存旧值。
					POINT pt;
					pt.load= point[1].load;
					pt.ad= point[1].ad;
					pt.used= point[1].used;
					
					seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
					
					tmp8[0]= ' ';
					if('C' == tmp8[1])
						tmp8[1]= ' ';			//去掉第1个数码管的'C'。
					tmp8[7]='\0';
					point[1].load= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
					point[1].ad= ad;
					point[1].used= 1;
					
									
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
						uartS("\nsave load 1");
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);

						sta= 0;
						seg_flash_all(0);
						
						
						//准备恢复校准过程中的滤波强度。
						flag_para_update_fir= 'X';
					}
					else{		
						point[1].load= pt.load;		//保存失败，恢复旧值（断电完蛋）。
						point[1].ad= pt.ad;
						point[1].used= pt.used;
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save load 1");
						osDelay(1000);
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//准备恢复校准过程中的滤波强度。
					flag_para_update_fir= 'X';
				}
				
				break;				
			
			default:
				break;
		}
	}
	else if(msg.type == MSG_TYPE_MV_WT){
		uartS("\nmv");
		if(disp_mv){
			//显示mv值。
			seg_mv_to_seg(msg.uv, msg.dat[0]);
			set_one_seg(1,'C',0);
			
			ad= msg.ad;
		}	
	}
}






/*标定第2点叶子菜单项处理函数。
先显示LoAD2，确定后显示"Add ld"约1秒后，显示mv值。再确定，如果此时STAB有效，则进入设置标定2的称重值；无效（不稳）则死等。QQ如何退出死等状态？
在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
*/
void leaf_Fn_cal_load2(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_flash= 1;	//有效范围：1~6
	static uint8_t disp_mv= 0;		//是否显示mv值。
	static int32_t ad;				//和uV伴随而来的ad值。
	uint16_t key;	
	char tmp8[8];
	
	
	if(msg.type == MSG_TYPE_KEY){
		key= msg.key;
		
		switch (sta){
			case 0:	
				if(KEY_K4_ENTER == key){
					seg_updata("Add ld ");
					osDelay(1000);
					
					disp_mv=1;
					mode_mv_wt= MODE_MV;
					
					sta= 1;
					
					//准备调整校准过程中的滤波强度。
					flag_para_update_fir= 'C';
				}
				else if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	
				}
				else if(KEY_K1_ESC == key){
					//返回上一级菜单。
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);
				}
				
				break;
				
			case 1:
				if(key == KEY_K4_ENTER){
					
					//需要判断当前STAB为1才能保存，否则什么也不做。
					if(seg_stab_sta()){
						disp_mv= 0;	//停止动态显示
						
						//保存当前mv值。
						seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
					
						tmp8[0]= ' ';
						if('C' == tmp8[1])
							tmp8[1]= ' ';			//去掉第1个数码管的'C'。
						tmp8[7]='\0';
						point[2].uv= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
						
						
						//
						seg_updata("000000 ");
						idx_flash= 1;
						set_one_seg_flash(idx_flash, SEG_FLASH);
						set_one_seg_point(6-para_xxx.pos_dot, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
						
						sta= 2;
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//滤波强度要恢复。
					flag_para_update_fir= 'X';
				}
				
				break;
				
			case 2:
				//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
				if(key == KEY_K2_OPT){
					inc_one_seg(idx_flash);
				}
				else if(key == KEY_K3_MODE){
					set_one_seg_flash(idx_flash, SEG_LIGHT);
					
					idx_flash++;
					if(6< idx_flash)
						idx_flash= 1;
					set_one_seg_flash(idx_flash, SEG_FLASH);
				}
				else if(key == KEY_K4_ENTER){
					//保存旧值。
					POINT pt;
					pt.load= point[2].load;
					pt.ad= point[2].ad;
					pt.used= point[2].used;
					
					seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
					
					tmp8[0]= ' ';
					if('C' == tmp8[1])
						tmp8[1]= ' ';			//去掉第1个数码管的'C'。
					tmp8[7]='\0';
					point[2].load= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
					point[2].ad= ad;
					point[2].used= 1;
					
									
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
						uartS("\nsave load 2");
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);

						sta= 0;
						seg_flash_all(0);
						
						//准备恢复校准过程中的滤波强度。
						flag_para_update_fir= 'X';
					}
					else{		
						point[2].load= pt.load;		//保存失败，恢复旧值（断电完蛋）。
						point[2].ad= pt.ad;
						point[2].used= pt.used;
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save load 2");
						osDelay(1000);
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//准备恢复校准过程中的滤波强度。
					flag_para_update_fir= 'X';
				}
				
				break;				
			
			default:
				break;
		}
	}
	else if(msg.type == MSG_TYPE_MV_WT){
		uartS("\nmv");
		if(disp_mv){
			//显示mv值。
			seg_mv_to_seg(msg.uv, msg.dat[0]);
			set_one_seg(1,'C',0);
						
			ad= msg.ad;
		}	
	}
}




/*标定第3点叶子菜单项处理函数。
先显示LoAD3，确定后显示"Add ld"约1秒后，显示mv值。再确定，如果此时STAB有效，则进入设置标定3的称重值；无效（不稳）则死等。QQ如何退出死等状态？
在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
*/
void leaf_Fn_cal_load3(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_flash= 1;	//有效范围：1~6
	static uint8_t disp_mv= 0;		//是否显示mv值。
	static int32_t ad;				//和uV伴随而来的ad值。
	uint16_t key;	
	char tmp8[8];
	
	
	if(msg.type == MSG_TYPE_KEY){
		key= msg.key;
		
		switch (sta){
			case 0:	
				if(KEY_K4_ENTER == key){
					seg_updata("Add ld ");
					osDelay(1000);
					
					disp_mv=1;
					mode_mv_wt= MODE_MV;
					
					sta= 1;
					
					//准备调整校准过程中的滤波强度。
					flag_para_update_fir= 'C';
				}
				else if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	
				}
				else if(KEY_K1_ESC == key){
					//返回上一级菜单。
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);
				}
				
				break;
				
			case 1:
				if(key == KEY_K4_ENTER){
					
					//需要判断当前STAB为1才能保存，否则什么也不做。
					if(seg_stab_sta()){
						
						disp_mv= 0;	//停止动态显示
						
						//保存当前mv值。
						seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
					
						tmp8[0]= ' ';
						if('C' == tmp8[1])
							tmp8[1]= ' ';			//去掉第1个数码管的'C'。
						tmp8[7]='\0';
						point[3].uv= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
						
						
						//
						seg_updata("000000 ");
						idx_flash= 1;
						set_one_seg_flash(idx_flash, SEG_FLASH);
						set_one_seg_point(6-para_xxx.pos_dot, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
						
						sta= 2;
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//滤波强度要恢复。
					flag_para_update_fir= 'X';
				}
				
				break;
				
			case 2:
				//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
				if(key == KEY_K2_OPT){
					inc_one_seg(idx_flash);
				}
				else if(key == KEY_K3_MODE){
					set_one_seg_flash(idx_flash, SEG_LIGHT);
					
					idx_flash++;
					if(6< idx_flash)
						idx_flash= 1;
					set_one_seg_flash(idx_flash, SEG_FLASH);
				}
				else if(key == KEY_K4_ENTER){
					//保存旧值。
					POINT pt;
					pt.load= point[3].load;
					pt.ad= point[3].ad;
					pt.used= point[3].used;
					
					seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
					
					tmp8[0]= ' ';
					if('C' == tmp8[1])
						tmp8[1]= ' ';			//去掉第1个数码管的'C'。
					tmp8[7]='\0';
					point[3].load= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
					point[3].ad= ad;
					point[3].used= 1;
					
									
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
						uartS("\nsave load 3");
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);

						sta= 0;
						seg_flash_all(0);
						
						//准备恢复校准过程中的滤波强度。
						flag_para_update_fir= 'X';
					}
					else{		
						point[3].load= pt.load;		//保存失败，恢复旧值（断电完蛋）。
						point[3].ad= pt.ad;
						point[3].used= pt.used;
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save load 3");
						osDelay(1000);
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//准备恢复校准过程中的滤波强度。
					flag_para_update_fir= 'X';
				}
				
				break;				
			
			default:
				break;
		}
	}
	else if(msg.type == MSG_TYPE_MV_WT){
		uartS("\nmv");
		if(disp_mv){
			//显示mv值。
			seg_mv_to_seg(msg.uv, msg.dat[0]);
			set_one_seg(1,'C',0);
			
			ad= msg.ad;
		}	
	}
}



/*标定第4点叶子菜单项处理函数。
先显示LoAD4，确定后显示"Add ld"约1秒后，显示mv值。再确定，如果此时STAB有效，则进入设置标定4的称重值；无效（不稳）则死等。QQ如何退出死等状态？
在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
*/
void leaf_Fn_cal_load4(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_flash= 1;	//有效范围：1~6
	static uint8_t disp_mv= 0;		//是否显示mv值。
	static int32_t ad;				//和uV伴随而来的ad值。
	uint16_t key;
	char tmp8[8];
	
	
	if(msg.type == MSG_TYPE_KEY){
		key= msg.key;
		
		switch (sta){
			case 0:	
				if(KEY_K4_ENTER == key){
					seg_updata("Add ld ");
					osDelay(1000);
					
					disp_mv=1;
					mode_mv_wt= MODE_MV;
					
					sta= 1;
					
					//滤波强度要变强。
					flag_para_update_fir= 'C';
				}
				else if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	
				}
				else if(KEY_K1_ESC == key){
					//返回上一级菜单。
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);
				}
				
				break;
				
			case 1:
				if(key == KEY_K4_ENTER){
					
					//需要判断当前STAB为1才能保存，否则什么也不做。
					if(seg_stab_sta()){
						disp_mv= 0;	//停止动态显示
						
						//保存当前mv值。
						seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
					
						tmp8[0]= ' ';
						if('C' == tmp8[1])
							tmp8[1]= ' ';			//去掉第1个数码管的'C'。
						tmp8[7]='\0';
						point[4].uv= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
						
						
						//
						seg_updata("000000 ");
						idx_flash= 1;
						set_one_seg_flash(idx_flash, SEG_FLASH);
						set_one_seg_point(6-para_xxx.pos_dot, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
						
						sta= 2;
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//滤波强度要恢复。
					flag_para_update_fir= 'X';
				}
				
				break;
				
			case 2:
				//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
				if(key == KEY_K2_OPT){
					inc_one_seg(idx_flash);
				}
				else if(key == KEY_K3_MODE){
					set_one_seg_flash(idx_flash, SEG_LIGHT);
					
					idx_flash++;
					if(6< idx_flash)
						idx_flash= 1;
					set_one_seg_flash(idx_flash, SEG_FLASH);
				}
				else if(key == KEY_K4_ENTER){
					//保存旧值。
					POINT pt;
					pt.load= point[4].load;
					pt.ad= point[4].ad;
					pt.used= point[4].used;
					
					seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
					
					tmp8[0]= ' ';
					if('C' == tmp8[1])
						tmp8[1]= ' ';			//去掉第1个数码管的'C'。
					tmp8[7]='\0';
					point[4].load= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
					point[4].ad= ad;
					point[4].used= 1;
					
									
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
						uartS("\nsave load 4");
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);

						sta= 0;
						seg_flash_all(0);
						
						//准备恢复校准过程中的滤波强度。
						flag_para_update_fir= 'X';
					}
					else{		
						point[4].load= pt.load;		//保存失败，恢复旧值（断电完蛋）。
						point[4].ad= pt.ad;
						point[4].used= pt.used;
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save load 4");
						osDelay(1000);
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//滤波强度要恢复。
					flag_para_update_fir= 'X';
				}
				
				break;				
			
			default:
				break;
		}
	}
	else if(msg.type == MSG_TYPE_MV_WT){
		uartS("\nmv");
		if(disp_mv){
			//显示mv值。
			seg_mv_to_seg(msg.uv, msg.dat[0]);
			set_one_seg(1,'C',0);
			
			ad= msg.ad;
		}	
	}
}




/*分度值叶子菜单项处理函数。1d不是Ld。
分度值：1/2/5/10/20/50。索引：0，1，2，3，4，5。有些麻烦啊，索引---真实值
*/
void leaf_Fn_cal_1d(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint16_t val_change= 1;	//有效范围：[0, 5] -> 1/2/5/10/20/50.
	char tmp8[8];
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取现有分度值并闪显。
				val_change= 0;	//默认值（若未在tbl_fd[]中找到，也是这个值）
				for(int i= 0; i<6; i++){
					if(para_xxx.fd_min == tbl_fd[i]){
						val_change= i;
						break;
					}
				}
				
				show_1d(val_change, tmp8);
				seg_updata(tmp8);
				
				set_one_seg_flash(5, SEG_FLASH);
				set_one_seg_flash(6, SEG_FLASH);
				
				sta= 1;
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc ld");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//调整分度值。
				if(5<= val_change)
					val_change= 0;
				else
					val_change++;

				show_1d(val_change, tmp8);
				seg_updata(tmp8);
				
			}
			else if(KEY_K3_MODE == key){
				//调整分度值。
				if(0 == val_change)
					val_change= 5;
				else
					val_change--;
				
				show_1d(val_change, tmp8);
				seg_updata(tmp8);
				
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.fd_min;
				para_xxx.fd_min= tbl_fd[val_change];
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.fd_min");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.fd_min= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.fd_min");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前分度值，在同级菜单循环切换？
				uartS("\nesc para_xxx.fd_min");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash_all(0);
			}
			break;
			
		default:
			break;
	}			

}


/*串口校准使能。
按OPT键进行切换（闪烁显示on或off），按Enter键进行确定。
*/
void leaf_Fn_cal_siocal(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t on_off= 0;	//有效范围：0,1.
	uint16_t key;	
	static uint8_t val_change;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			//当前显示“PASS”，等待按enter.
			if(KEY_K4_ENTER == key){
				//根据pwd_setup_sw的值显示
				val_change= para_self.ser_cal_sw; 
				
				if(val_change){
					seg_updata("    on ");
				}
				else{
					seg_updata("   off ");
				}	
				
				seg_flash_all(1);		
				sta= 1;
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
		case 1:
			//调整并确认
			if(KEY_K4_ENTER == key){
				//保存旧值。
				uint8_t val_tmp8= para_self.ser_cal_sw;
				para_self.ser_cal_sw= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.ser_cal_sw;");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_self.ser_cal_sw= val_tmp8;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.ser_cal_sw");
					osDelay(1000);
				}
			}
			else if(key == KEY_K2_OPT){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(key == KEY_K3_MODE){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(KEY_K1_ESC == key){		
				seg_updata(cur_item->content);
				
				sta= 0;
				seg_flash_all(0);
			}
			break;
			
		default:
			break;
	}			
}



/*PASS(设置密码)叶子菜单项处理函数。
*/
void leaf_Fn_cal_pass(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6。最高位为1。
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			//当前显示“PASS”，等待按enter.
			if(KEY_K4_ENTER == key){
				//显示"0----- ",并第1个数码管闪。
				seg_updata("0----- ");
				set_one_seg_flash(idx_seg, SEG_FLASH);
				
				sta= 1;
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
			
		case 1:
			//第1次调整密码并确认。
			if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				seg_copy_to_tmp(tmp);
				
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				if(('-' == tmp[idx_seg]) || ('=' == tmp[idx_seg]))
					set_one_seg(idx_seg,'0', 0);
			}
			else if(key == KEY_K4_ENTER){
				
				seg_copy_to_tmp(pass1);
				
				seg_updata("0===== ");
				seg_flash(0);
				idx_seg=1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				sta= 2;
			}
			else if(key == KEY_K1_ESC){
				seg_updata(cur_item->content);
				
				sta= 0;
				idx_seg= 1;
				seg_flash_all(0);
			}
			
			break;
			
		case 2:
			//第2次调整密码并确认。
			if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				seg_copy_to_tmp(tmp);
				
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				if(('-' == tmp[idx_seg]) || ('=' == tmp[idx_seg]))
					set_one_seg(idx_seg,'0', 0);
			}
			else if(key == KEY_K4_ENTER){
				
				seg_copy_to_tmp(tmp6);
				
				if(0 != pass_compare2(pass1, tmp6)){
					//2次密码不相同：显示错误后，重新开始。
					seg_updata("Error ");	//测试序列：PASS
					seg_flash_all(0);
					osDelay(2000);
					
					seg_updata("0----- ");
					
					idx_seg= 1;
					set_one_seg_flash(idx_seg, SEG_FLASH);
					
					sta= 1;
				}
				else{
					//保存旧值。
					uint8_t val_tmp8[6];
					for(uint8_t i= 0; i< 6; i++){
						val_tmp8[i]= para_self.pwd_cal[i];
						para_self.pwd_cal[i]= tmp6[i+1];
					}				
				
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
						uartS("\nsave pwd_cal");
					
						//设置密码ok
						seg_updata("SUCC ");
						osDelay(2000);
						
						seg_updata("CALEnd ");
						osDelay(2000);
						
						seg_flash_all(0);
						
						idx_seg= 1;
						sta= 0;
						cur_item= cur_item->parent;
						seg_updata(cur_item->content);
					}
					else{
						for(uint8_t i= 0; i< 6; i++){
							para_self.pwd_cal[i]= val_tmp8[i];	//保存失败，恢复旧值（断电完蛋）。
						}	
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save pwd_cal");
						osDelay(1000);
					};
				}
			}
			else if(key == KEY_K1_ESC){
				seg_updata(cur_item->content);
				
				sta= 0;
				idx_seg= 1;
				seg_flash_all(0);
			}
			
			break;
			
		default:
			break;
	}
}



/*读取过程中，显示"---"，读取完成并CRC8校验成功，显示"     o"。
*/
void leaf_Fn_cal_RdP(MSG_U msg)
{
	static uint8_t sta= 0;
	char tmp8[8];
	static uint8_t val_idx;
	uint16_t key;	
	static uint8_t val_change;
	uint8_t idx_max;	//每次计算，也是合适。
	char str[64];
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				seg_updata("   ---");
				
				//读取传感器侧的单线芯片。
				POINT pt_tmp[7];
				POINT pt_bk[5];
				int32_t cp_tmp;	//临时最大量程
				uint16_t cp_H, cp_L;
				
				uint8_t crc8;
				uint8_t u8array[16*5+4];
				//将ds28的页0 -->pt_tmp[0]
				ds28_rd_page(0, (uint8_t*)&pt_tmp[0]);	//无POINT.cp。
				ds28_rd_page(1, (uint8_t*)&pt_tmp[1]);	//无POINT.cp。
				ds28_rd_page(2, (uint8_t*)&pt_tmp[2]);	//无POINT.cp。
				ds28_rd_page(3, (uint8_t*)&pt_tmp[3]);	//无POINT.cp。
				ds28_rd_page(4, (uint8_t*)&pt_tmp[4]);	//无POINT.cp。
				
				ds28_rd_page(5, (uint8_t*)&pt_tmp[5]);	//最大量程
				ds28_rd_page(6, (uint8_t*)&pt_tmp[6]);	//CRC8
				
				//先计算crc是否正确
				crc8= (uint8_t)pt_tmp[6].used;
				
				memcpy(u8array+ 16*0, (uint8_t*)&pt_tmp[0], 16);
				memcpy(u8array+ 16*1, (uint8_t*)&pt_tmp[1], 16);
				memcpy(u8array+ 16*2, (uint8_t*)&pt_tmp[2], 16);
				memcpy(u8array+ 16*3, (uint8_t*)&pt_tmp[3], 16);
				memcpy(u8array+ 16*4, (uint8_t*)&pt_tmp[4], 16);
				memcpy(u8array+ 16*5, (uint8_t*)&pt_tmp[5], 4);	//最大量程
				
				crc8= Crc8_Cal(u8array, 16*5+4);
				
				if(crc8 != (uint8_t)pt_tmp[6].used){
					//读取后CRC8不对，可以重试。
					seg_updata("Err101");
					
					uartS("err:CRC8");
					
					break;
				}
				
				sprintf(str, "\n cp=%d, crc 0k", pt_tmp[5].used);
				uartS(str);
				
				//将pt_tmp[]更新到point[]，保存前先备份（好像没用）。
				uint8_t kk= 0;
				
				pt_bk[kk].used= point[kk].used;
				pt_bk[kk].uv= point[kk].uv;
				pt_bk[kk].ad= point[kk].ad;
				pt_bk[kk].load= point[kk].load;
				point[kk].used= pt_tmp[kk].used;
				point[kk].uv= pt_tmp[kk].uv;
				point[kk].ad= pt_tmp[kk].ad;
				point[kk].load= pt_tmp[kk].load;
				
				kk++;	
				//k=1
				pt_bk[kk].used= point[kk].used;
				pt_bk[kk].uv= point[kk].uv;
				pt_bk[kk].ad= point[kk].ad;
				pt_bk[kk].load= point[kk].load;
				point[kk].used= pt_tmp[kk].used;
				point[kk].uv= pt_tmp[kk].uv;
				point[kk].ad= pt_tmp[kk].ad;
				point[kk].load= pt_tmp[kk].load;
				
				kk++;	
				//k=2
				pt_bk[kk].used= point[kk].used;
				pt_bk[kk].uv= point[kk].uv;
				pt_bk[kk].ad= point[kk].ad;
				pt_bk[kk].load= point[kk].load;
				point[kk].used= pt_tmp[kk].used;
				point[kk].uv= pt_tmp[kk].uv;
				point[kk].ad= pt_tmp[kk].ad;
				point[kk].load= pt_tmp[kk].load;
				
				kk++;	
				//k=3
				pt_bk[kk].used= point[kk].used;
				pt_bk[kk].uv= point[kk].uv;
				pt_bk[kk].ad= point[kk].ad;
				pt_bk[kk].load= point[kk].load;
				point[kk].used= pt_tmp[kk].used;
				point[kk].uv= pt_tmp[kk].uv;
				point[kk].ad= pt_tmp[kk].ad;
				point[kk].load= pt_tmp[kk].load;
				
				kk++;	
				//k=4
				pt_bk[kk].used= point[kk].used;
				pt_bk[kk].uv= point[kk].uv;
				pt_bk[kk].ad= point[kk].ad;
				pt_bk[kk].load= point[kk].load;
				point[kk].used= pt_tmp[kk].used;
				point[kk].uv= pt_tmp[kk].uv;
				point[kk].ad= pt_tmp[kk].ad;
				point[kk].load= pt_tmp[kk].load;
				
				
				cp_H= para_xxx.fs_max_hi;
				cp_L= para_xxx.fs_max_lo;
				para_xxx.fs_max_hi= pt_tmp[5].used>> 16;
				para_xxx.fs_max_lo= pt_tmp[5].used;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave point[] and CP from DS28 to para_xxx");
					
					seg_updata("     o");
					osDelay(1000);
					
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					//编程失败，恢复之前值到RAM（QQ!!但未将这些值写入FLASH）。
					para_xxx.fs_max_hi= cp_H;
					para_xxx.fs_max_lo= cp_L;
					
					uint8_t kk= 0;
					
					point[kk].used= pt_bk[kk].used;
					point[kk].uv= pt_bk[kk].uv;
					point[kk].ad= pt_bk[kk].ad;
					point[kk].load= pt_bk[kk].load;
					
					kk++;
					point[kk].used= pt_bk[kk].used;
					point[kk].uv= pt_bk[kk].uv;
					point[kk].ad= pt_bk[kk].ad;
					point[kk].load= pt_bk[kk].load;
					
					kk++;
					point[kk].used= pt_bk[kk].used;
					point[kk].uv= pt_bk[kk].uv;
					point[kk].ad= pt_bk[kk].ad;
					point[kk].load= pt_bk[kk].load;
					
					kk++;
					point[kk].used= pt_bk[kk].used;
					point[kk].uv= pt_bk[kk].uv;
					point[kk].ad= pt_bk[kk].ad;
					point[kk].load= pt_bk[kk].load;
					
										
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save point[] and CP from DS28");
					
					osDelay(1000);
				}
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc unit");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		default:
			break;
	}
}


/*保存过程中，显示"---"，保存成功，显示"     o"，保存失败显示“Err100"。
保存过程，是将仪表已标定值point[5]写入单线芯片，并增加CRC8。
保存后，不必回读验证，因为写入函数已有回读（且回读是DS28E写入流程的一步）。
*/
void leaf_Fn_cal_SaP(MSG_U msg)
{
	static uint8_t sta= 0;
	char tmp8[8];
	static uint8_t val_idx;
	uint16_t key;	
	static uint8_t val_change;
	uint8_t idx_max;	//每次计算，也是合适。
	char str[48];
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				seg_updata("   ---");
				
				//读取传感器侧的单线芯片。
				POINT pt_tmp;			//用于写入最大量程和CRC8。
				POINT pt_readback;			//用于写入最大量程和CRC8。
				uint32_t cp_tmp;		//临时最大量程
				uint16_t cp_H, cp_L;
				
				uint8_t crc8;
				uint8_t u8array[16*5+4];
				
				pt_tmp.used= para_xxx.fs_max_hi;
				pt_tmp.used<<= 16;
				pt_tmp.used|= para_xxx.fs_max_lo;
				pt_tmp.ad= 0x0;
				pt_tmp.uv= 0x0;
				pt_tmp.load= 0x0;
				
//				//赋值（假的值）
//				point[0].used= 1;
//				point[0].ad= 0x123458;
//				point[0].uv= 0x123457;
//				point[0].load= 0x123459;
//				
//				point[1].used= 1;
//				point[1].ad= 0x11ABCB;
//				point[1].uv= 0x11ABCC;
//				point[1].load= 0x11ABCD;
//				
//				point[2].used= 1;
//				point[2].ad= 0x12ABCB;
//				point[2].uv= 0x12ABCC;
//				point[2].load= 0x12ABCD;
//				
//				point[3].used= 0;
//				point[3].ad= 0x13ABCB;
//				point[3].uv= 0x13ABCC;
//				point[3].load= 0x13ABCD;
//				
//				point[4].used= 0;
//				point[4].ad= 0x14ABCB;
//				point[4].uv= 0x14ABCC;
//				point[4].load= 0x14ABCD;
				
				
				memcpy(u8array+ 16*0, (uint8_t*)&point[0], 16);
				memcpy(u8array+ 16*1, (uint8_t*)&point[1], 16);
				memcpy(u8array+ 16*2, (uint8_t*)&point[2], 16);
				memcpy(u8array+ 16*3, (uint8_t*)&point[3], 16);
				memcpy(u8array+ 16*4, (uint8_t*)&point[4], 16);
				memcpy(u8array+ 16*5, (uint8_t*)&pt_tmp, 4);	//最大量程
				
				crc8= Crc8_Cal(u8array, 16*5+4);				//得到CRC8。
				
				//将ds28的页0 -->pt_tmp[0]
				if(0 != ds28_wr_page(0, (uint8_t*)&point[0])){	//无POINT.cp。
					uartS("err:wr DS28 p0");
					break;
				}
				uartS("\nwr DS28 p0 ok");
				
				
				if(0 != ds28_wr_page(1, (uint8_t*)&point[1])){	//无POINT.cp。
					uartS("err:wr DS28 p1");
					break;
				}	
				uartS("\nwr DS28 p1 ok");
				
				if(0 != ds28_wr_page(2, (uint8_t*)&point[2])){	//无POINT.cp。
					uartS("err:wr DS28 p2");
					break;
				}
				uartS("\nwr DS28 p2 ok");
				
				if(0 != ds28_wr_page(3, (uint8_t*)&point[3])){	//无POINT.cp。
					uartS("err:wr DS28 p3");
					break;
				}
				uartS("\nwr DS28 p3 ok");
				
				if(0 != ds28_wr_page(4, (uint8_t*)&point[4])){	//无POINT.cp。
					uartS("err:wr DS28 p4");
					break;
				}
				uartS("\nwr DS28 p4 ok");
				
				
				
				if(0 != ds28_wr_page(5, (uint8_t*)&pt_tmp)){	//最大量程
					uartS("err:wr DS28 cp");
					break;
				}
				uartS("\nwr DS28 p5 ok");
				
				pt_tmp.used= crc8;
				if(0 != ds28_wr_page(6, (uint8_t*)&pt_tmp) ){	//CRC8
					uartS("err:wr DS28 crc8");
					break;
				}
				uartS("\nwr DS28 p6 ok");
				
				ds28_rd_page(0, (uint8_t*)&pt_readback);
				sprintf(str, "\npt0: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
				uartS(str);
				
				ds28_rd_page(1, (uint8_t*)&pt_readback);
				sprintf(str, "\npt1: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
				uartS(str);
				
				ds28_rd_page(2, (uint8_t*)&pt_readback);
				sprintf(str, "\npt2: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
				uartS(str);
				
				ds28_rd_page(3, (uint8_t*)&pt_readback);
				sprintf(str, "\npt3: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
				uartS(str);
				
				ds28_rd_page(4, (uint8_t*)&pt_readback);
				sprintf(str, "\npt4: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
				uartS(str);
				
				ds28_rd_page(5, (uint8_t*)&pt_readback);
				sprintf(str, "\npt5: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
				uartS(str);
				
				ds28_rd_page(6, (uint8_t*)&pt_readback);
				sprintf(str, "\npt6: %08x-%02x", pt_readback.used, (uint8_t)pt_readback.used);
				uartS(str);
				
				
				//保存成功，显示"    o"。
				seg_updata("     o");
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc SA P  ");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		default:
			break;
	}
}



/*setup下级菜单IN进入时处理函数。
*/
void enter_Fn_setup_in(void)
{
	if(0 == para_self.pwd_setup_sw){
		//禁止参数设置密码，则直接进入IN下一个菜单项。
		cur_item= cur_item->sibble;	
		seg_updata(cur_item->content);
	}
}



/*进入校准流程的叶子菜单项处理函数。即完成密码验证。
和F1，F2...并列。
*/
void setup_in_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static uint8_t cnt_pass_err= 0;	//密码错误次数，但4次时锁定（只能关电）。
	static char tmp6[7];		//有效范围：1~6.	
	uint16_t key;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				sta= 1;
				seg_updata("000000");	//测试序列：PASS
				//第1个‘0’闪
				idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			cnt_pass_err=0;
			
			break;
		case 1:
			//输入密码：按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
			if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);	
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				
				seg_copy_to_tmp(tmp6);
				//比较密码，如果正确，进入下一个邻居菜单。
				if(0UL == pass_setup_compare(tmp6)){
					sta= 0;
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	//cur_item->f_enter();
					
					set_one_seg_flash(idx_seg, SEG_LIGHT);	//关闭闪烁
				}
				else{
					cnt_pass_err++;
					//否则，显示Error为1秒。
					seg_copy_to_tmp(tmp6);
					set_one_seg_flash(idx_seg, SEG_LIGHT);	//关闭闪烁
					
					if(1 == cnt_pass_err)
						seg_updata("Error1");
					else if(2 == cnt_pass_err)
						seg_updata("Error2");
					else if(3 == cnt_pass_err)
						seg_updata("Error3");
					else if(4 == cnt_pass_err){
						seg_updata("Error4");
						while(1);
					}
					osDelay(2000);
					seg_updata("000000");
					
					idx_seg= 1;
					set_one_seg_flash(idx_seg, SEG_FLASH);
				}
			}
			else{
				//不处理
			}
			
			break;
		default:
			break;
	}
	

}	



/*SETUP菜单下F11叶子菜单处理函数：上电清零开关（on/oFF）。
*/
void setup_F11_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	uint16_t key;	
	static uint16_t val_change;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			//当前显示“PASS”，等待按enter.
			if(KEY_K4_ENTER == key){
				//根据pwd_setup_sw的值显示
				val_change= para_xxx.zero_auto_sw; 
				
				if(val_change){
					seg_updata("    on ");
				}
				else{
					seg_updata("   off ");
				}	
				
				seg_flash_all(1);		
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;	
		
		case 1:
			//第1次调整密码并确认。
			if(key == KEY_K2_OPT){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(key == KEY_K3_MODE){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.zero_auto_sw;
				para_xxx.zero_auto_sw= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.zero_auto_sw");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.zero_auto_sw= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.zero_auto_sw");
					osDelay(1000);
				}
			}
			else if( KEY_K1_ESC == key ){		
				seg_updata(cur_item->content);
				
				sta= 0;
				seg_flash_all(0);
			}
			break;
			
		default:
			break;
	}	
}

/*SETUP菜单下F12叶子菜单处理函数：零点跟踪范围（0~9d）。
*/
void setup_F12_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	char tmp8[8];
	uint16_t key;	
	static uint16_t val_change;
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(9< para_xxx.range_zero_trace)
					para_xxx.range_zero_trace= 0;
				
				val_change= para_xxx.range_zero_trace;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc range_trance");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(9<= val_change)
					val_change= 0;
				else
					val_change++;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				
				if(0 ==  val_change)
					val_change= 9;
				else
					val_change--;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.range_zero_trace;
				para_xxx.range_zero_trace= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.range_zero_trace");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.range_zero_trace= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.range_zero_trace");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc para_xxx.range_zero_trace");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}			
}



/*SETUP菜单下F13叶子菜单处理函数：判稳范围（1~9d）。
*/
void setup_F13_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t dat= 1;			//有效范围：1~9.
	static uint8_t idx_seg= 6;		//固定为6
	char tmp8[8];
	uint16_t key;
	static uint16_t val_change;		//临时判稳范围变量。	
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取判稳范围并闪显。
				if(9< para_xxx.range_stab)
					val_change= 1;
				
				val_change= para_xxx.range_stab;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc range_stab");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(9<= val_change)
					val_change= 1;
				else
					val_change++;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				if(1>= val_change)
					val_change= 9;
				else
					val_change--;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.range_stab;
				para_xxx.range_stab= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.range_stab");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.range_stab= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.range_stab");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc para_xxx.range_stab");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}



/*SETUP菜单下F14叶子菜单处理函数：清零范围（00~99%）。
*/
void setup_F14_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t dat= 1;			//有效范围：0~99.
	static uint8_t idx_seg= 6;		//固定为6
	char tmp8[8];
	static uint16_t val_change;	//临时清零范围变量。
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取判稳范围并闪显。
				if(99< para_xxx.range_zero)
					para_xxx.range_zero= 0;
				
				val_change= para_xxx.range_zero;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc range_zero");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+10。
				val_change+=10;
				if(99< val_change)
					val_change%= 10;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值+1。
				if(99<= val_change)
					val_change%= 10;
				else 
					val_change++;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.range_zero;
				para_xxx.range_zero= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.range_zero");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.range_zero= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.range_zero");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc para_xxx.range_zero");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}


/*SETUP菜单下F15叶子菜单处理函数：数字滤波参数（0~9，0--无滤波，9--最强滤波）。
实现类比F12。
*/
void setup_F15_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t dat= 1;		//有效范围：0~9.
	static uint8_t idx_seg= 6;	//固定为6
	char tmp8[8];
	static uint16_t val_change;
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(9< para_xxx.filter_dig)
					para_xxx.filter_dig= 0;
				
				val_change= para_xxx.filter_dig;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc filter_dig");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(9<= val_change)
					val_change= 0;
				else
					val_change++;
					
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				//inc_one_seg(idx_seg);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				if(0< val_change)
					val_change--;
				else
					val_change= 9;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				//dec_one_seg(idx_seg);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.filter_dig;
				para_xxx.filter_dig= val_change;
				
					
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.filter_dig");
					
					//update_window_size();			//已在Thread_Para()中更新了二次参数。
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
					
					flag_para_update_fir= 1;		//更新FIR标志
				}
				else{
					para_xxx.filter_dig= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.filter_dig");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc filter_dig");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}			
}


/*SETUP菜单下F16叶子菜单处理函数：稳态滤波（0~9，0--无滤波，9--最强滤波）。
实现类比F12。
*/
void setup_F16_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t dat= 1;		//有效范围：0~9.
	static uint8_t idx_seg= 6;	//固定为6
	char tmp8[8];
	static uint16_t val_change;
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(9< para_xxx.filter_stab)
					para_xxx.filter_stab= 0;
				
				val_change= para_xxx.filter_stab;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc filter_stab");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(9<= val_change)
					val_change= 0;
				else
					val_change++;
					
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				//inc_one_seg(idx_seg);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				if(0< val_change)
					val_change--;
				else
					val_change= 9;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				//dec_one_seg(idx_seg);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.filter_stab;
				para_xxx.filter_stab= val_change;
					
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.filter_stab");
					
					//update_stab_size_err();			//已在Thread_Para()中更新了二次参数。
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.filter_stab= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.filter_stab");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc filter_stab");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}				
}

/*SETUP菜单下F17叶子菜单处理函数：AD采样速率：0:120次/s  1:480次/s2:960次/s。
*/
void setup_F17_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t dat= 1;		//有效范围：0~2.
	static uint8_t idx_seg= 6;	//固定为6
	char tmp8[8];
	static uint16_t val_change;
	uint16_t key;	
	char str[32];
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(2< para_xxx.sps)
					para_xxx.sps= 0;
					
				val_change= para_xxx.sps;
				
				
				show_val(_tbl_adc_sps[val_change], tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc sps");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				val_change= 0;
//				if(2<= val_change)
//					val_change= 0;
//				else
//					val_change++;
				
				show_val(_tbl_adc_sps[val_change], tmp8);	//show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				val_change= 0;
//				if(0 == val_change)
//					val_change= 2;
//				else
//					val_change--;
				
				show_val(_tbl_adc_sps[val_change], tmp8);	//show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.sps;
				para_xxx.sps= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					sprintf(str, "\nsave para_xxx.sps= %d", _tbl_adc_sps[val_change]);
					uartS(str);
					
					flag_para_update_ad_sps=1;			
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
					
					//设置修改AD采样率标记，以在Thread_ADC()中修改AD采样率。
					flag_com_ad_sps= 1;
				}
				else{
					para_xxx.sps= val_tmp16;			//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.sps");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc sps");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}



/*SETUP菜单下F21叶子菜单处理函数：设置称号（Modbus从地址）。
*/
void setup_F21_leaf_Fn(MSG_U msg)
{	static uint8_t sta= 0;
	static uint8_t dat= 1;			//有效范围：0~99.
	static uint8_t idx_seg= 6;		//固定为6
	char tmp8[8];
	static uint8_t val_change;		//临时清零范围变量。
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取判稳范围并闪显。
				if(99< para_self.com_plc_addr){
					para_self.com_plc_addr= 0;
					
				}
				val_change= para_self.com_plc_addr;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc sn_addr");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+10。
				val_change+=10;
				if(99< val_change)
					val_change%= 10;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值+1。
				val_change++;
				if(99<= val_change)
					val_change%= 10;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint8_t val_tmp8= para_self.com_plc_addr;
				para_self.com_plc_addr= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.addr");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
					
					//设置修改AD采样率标记，以在Thread_ADC()中修改AD采样率。
					flag_com_ad_sps= 1;
				}
				else{
					para_self.com_plc_addr= val_tmp8;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.addr");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc sn_addr");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}



/*SETUP菜单下F22叶子菜单处理函数：设置波特率。
波特率：
0	9600");
1	19200");
2	38400");
3	57600");
*/
void setup_F22_leaf_Fn(MSG_U msg)
{	static uint8_t sta= 0;
	static uint8_t dat= 1;			//有效范围：0~99.
	static uint8_t idx_seg= 6;		//固定为6
	char tmp8[8];
	static uint8_t tmp_com_baud;	//临时波特率变量，范围0~3.。
	uint16_t key;	
	uint8_t idx_max;	//每次计算，也是合适。
	
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	idx_max= find_int32_cnt(_tbl_plc_baud);
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取波特率并闪显。
				if( idx_max < para_self.com_plc_baud_idx)
					para_self.com_plc_baud_idx= 0;
				
				tmp_com_baud= para_self.com_plc_baud_idx;
				
				show_val(_tbl_plc_baud[tmp_com_baud], tmp8);	//show_com_baud(tmp_com_baud, tmp8);
				seg_updata(tmp8);
				
				seg_flash_all(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc com_plc_baud_idx");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(idx_max<= tmp_com_baud)
					tmp_com_baud= 0;
				else
					tmp_com_baud++;
				
				show_val(_tbl_plc_baud[tmp_com_baud], tmp8);	//show_com_baud(tmp_com_baud, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				if(0 == tmp_com_baud)
					tmp_com_baud= idx_max;
				else
					tmp_com_baud--;
				
				show_val(_tbl_plc_baud[tmp_com_baud], tmp8);	//show_com_baud(tmp_com_baud, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_self.com_plc_baud_idx;
				para_self.com_plc_baud_idx= tmp_com_baud;
				
//				if(0 == tmp_com_baud)
//					para_self.com_plc_baud_idx= tmp_com_baud;	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
//				else if(1 == tmp_com_baud)
//					para_self.com_plc_baud_idx= 19200;
//				else if(2 == tmp_com_baud)
//					para_self.com_plc_baud_idx= 38400;
//				else if(3 == tmp_com_baud)
//					para_self.com_plc_baud_idx= 57600;
//				else
//					para_self.com_plc_baud_idx= 9600;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.com_plc_baud_idx");
					
					flag_para_update_com= 1;		//设置硬件重初始化标志。
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
					
					flag_para_update_com= 1;	//flag_com_modify= 1;	作废flag_com_modify。
				}
				else{
					para_self.com_plc_baud_idx= val_tmp16;	//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.com_plc_baud_idx");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc com_plc_baud_idx");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}



/*SETUP菜单下F23叶子菜单处理函数：设置串口通信方式。
*/
void setup_F23_leaf_Fn(MSG_U msg)
{	static uint8_t sta= 0;
	static uint8_t dat= 1;			//有效范围：0~99.
	static uint8_t idx_seg= 6;		//固定为6
	char tmp8[8];
	static uint8_t tmp_com_mode;	//临时波特率变量，范围0~3.。
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取波特率并闪显。
				if(0< para_self.com_mode){
					para_self.com_mode= 0;
				}
				
				tmp_com_mode= para_self.com_mode;
				show_com_mode(tmp_com_mode, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc com_baud");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				tmp_com_mode= 0;
//				if(2<= tmp_com_mode)
//					tmp_com_mode= 0;
//				else
//					tmp_com_mode++;
				
				show_com_mode(tmp_com_mode, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				tmp_com_mode= 0;
//				if(0 == tmp_com_mode)
//					tmp_com_mode= 2;
//				else
//					tmp_com_mode--;
				
				show_com_mode(tmp_com_mode, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint8_t val_tmp8= para_self.com_mode;
				para_self.com_mode= tmp_com_mode;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.com_mode");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_self.com_mode= val_tmp8;	//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.com_mode");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc com_mode");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}




/*SETUP菜单下F23叶子菜单处理函数：设置数据帧格式。
0	7-E-1：7 位数据位，偶校验，1 位停止位；	//暂不支持
1	7-O-1：7 位数据位，奇校验，1 位停止位；	//暂不支持
2	8-E-1：8 位数据位，偶校验，1 位停止位；
3	8-O-1：8 位数据位，奇校验，1 位停止位；
4	8-n-1：8 位数据位，无校验，1 位停止位；
5	8-n-2：8 位数据位，无校验，2 位停止位；
*/
void setup_F24_leaf_Fn(MSG_U msg)
{	static uint8_t sta= 0;
	static uint8_t dat= 1;			//有效范围：0~99.
	static uint8_t idx_seg= 6;		//固定为6
	char tmp8[8];
	static uint8_t val_change;		//临时帧格式变量，范围0~5。
	uint16_t key;	
	uint8_t idx_max;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	idx_max= find_string_cnt(_tbl_plc_fmt);
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取帧格式并闪显。
				if(idx_max< para_self.com_plc_format_idx){
					para_self.com_plc_format_idx= 0;					
				}
				val_change= para_self.com_plc_format_idx;
				
				strcpy(tmp8, _tbl_plc_fmt[val_change]);		//show_com_format(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash_all(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc com_plc_format");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(idx_max<= val_change)
					val_change= 0;
				else
					val_change++;
				
				strcpy(tmp8, _tbl_plc_fmt[val_change]);		//show_com_format(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				if(0 == val_change)
					val_change= idx_max;
				else
					val_change--;
				
				strcpy(tmp8, _tbl_plc_fmt[val_change]);		//show_com_format(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint8_t val_tmp8= para_self.com_plc_format_idx;
				para_self.com_plc_format_idx= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.com_plc_format_idx");
					
					flag_para_update_com= 1;		//设置硬件重初始化标志。
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
					
					//设置修改PLC用串口波特率标记，以在Thread_PLC()中修改波特率。
					flag_para_update_com= 1;	//flag_com_modify= 1; 作废flag_com_modify。
				}
				else{
					para_self.com_plc_format_idx= val_tmp8;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.com_plc_format_idx");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc para_self.com_plc_format_idx");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}



/*SETUP菜单下F23叶子菜单处理函数：设置Modbus字节序。
*/
void setup_F25_leaf_Fn(MSG_U msg)
{	static uint8_t sta= 0;
	static uint8_t dat= 1;			//有效范围：0~99.
	static uint8_t idx_seg= 6;		//固定为6
	char tmp8[8];
	static uint8_t val_change;		//临时字节序变量，范围0~1。
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取波特率并闪显。
				if(1< para_self.hilo){
					para_self.hilo= 0;
					
				}
				val_change= para_self.hilo;
				
				show_hilo(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc hilo");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(val_change)
					val_change= 0;
				else
					val_change= 1;
				
				show_hilo(0, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				if(val_change)
					val_change= 0;
				else
					val_change= 1;
				
				show_hilo(0, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint8_t val_tmp8= para_self.hilo;
				para_self.hilo= 0;	//val_change;固定为0（hilo）。
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.hilo");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_self.hilo= val_tmp8;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.hilo");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc para_self.hilo");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}



/*SETUP菜单下F23叶子菜单处理函数：设置连续方式自动发送时间间隔。
0	none	//QQ
1	10
2	20
3	30
4	40
5	50
*/
void setup_F26_leaf_Fn(MSG_U msg)
{	static uint8_t sta= 0;
	static uint8_t dat= 1;				//有效范围：0~99.
	static uint8_t idx_seg= 6;			//固定为6
	char tmp8[8];
	static uint8_t val_change;			//临时发送间隔变量，范围0~5。
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取数据后闪显。
				if(5< para_self.com_interval){
					para_self.com_interval= 0;
				}
				
				val_change= para_self.com_interval;
					
				show_com_interval(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc com_interval");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(5<= val_change)
					val_change= 0;
				else
					val_change++;
				
				show_com_interval(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				if(0 == val_change)
					val_change= 5;
				else
					val_change--;
				
				show_com_interval(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint8_t val_tmp8= para_self.com_interval;
				para_self.com_interval= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.com_interval");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_self.com_interval= val_tmp8;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.com_interval");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc com_interval");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}



/*SETUP菜单下F31叶子菜单处理函数：模拟量输出方式。
0	电流输出4-20
1	电流输出0-20
2	电流0-24
3	电压0-5
4	电压0-10
5	电压-5-5	硬件不支持(shit,8个月后才知道硬件支持）
6	电压-10-10	硬件不支持(shit,8个月后才知道硬件支持）
7	自定义I_out，暂未实现
8	自定义V_out，暂未实现
*/
void setup_F31_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	char tmp8[8];				//有效范围：1~6.	
	uint16_t key;
	static uint32_t tmp_ana_out_mode;	//临时变量拷贝。
	uint8_t idx_max;
	
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	idx_max= find_string_cnt(_tbl_ana_out);
	key= msg.key;
	
	switch (sta){
		case 0:
			//当前显示“PASS”，等待按enter.
			if(KEY_K4_ENTER == key){
				//根据pwd_setup_sw的值显示
				if(idx_max< para_self.ana_out_mode)
					para_self.ana_out_mode= 0;
					
				tmp_ana_out_mode= para_self.ana_out_mode;
				strcpy(tmp8, _tbl_ana_out[tmp_ana_out_mode]);	//show_output_i_u(tmp_ana_out_mode, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}					
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				if(cur_item->sibble){
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);
				}					
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;	
		
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(idx_max<= tmp_ana_out_mode)
					tmp_ana_out_mode= 0;
				else
					tmp_ana_out_mode++;
				
				strcpy(tmp8, _tbl_ana_out[tmp_ana_out_mode]);	//show_output_i_u(tmp_ana_out_mode, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//显示值-1。
				if(0 == tmp_ana_out_mode)
					tmp_ana_out_mode= idx_max;
				else
					tmp_ana_out_mode--;
				
				strcpy(tmp8, _tbl_ana_out[tmp_ana_out_mode]);	//show_output_i_u(tmp_ana_out_mode, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint32_t val_tmp32= para_self.ana_out_mode;
				para_self.ana_out_mode= tmp_ana_out_mode;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.ana_out_mode");
				
					flag_para_update_dac= 1;		//设置硬件重初始化标志，再配合para_self.ana_out_mode是否变化。
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_self.ana_out_mode= val_tmp32;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.ana_out_mode");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc ana_out_mode");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}
}



/*SETUP菜单下F32叶子菜单处理函数：（模拟量输出）最小输出。
类比F32
暂未实现。
*/
void setup_F32_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	char tmp8[8];
	uint16_t key;	
	
	uint32_t* p;	
	int32_t* pi;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
		
	
	switch (sta){
		case 0:	
			if(KEY_K4_ENTER == key){
				//进入最大量程设置，并显示“100000”。!!不读取当前量程。
				if(ANA_I_DEF == para_self.ana_out_mode){
					if(999999< para_self.ana_out_min)
						para_self.ana_out_min= 999999;
					
					sprintf(tmp6,"%06d", para_self.ana_out_min);	//
					seg_updata(tmp6);
						
					set_one_seg_flash(1, SEG_FLASH);
					set_one_seg_point(3, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
					
					sta= 1;
				}
				else if(ANA_V_DEF == para_self.ana_out_mode){
					if(999999< para_self.ana_out_v_min)
						para_self.ana_out_v_min= 999999;
					
					if(para_self.ana_out_v_min< -99999)
						para_self.ana_out_v_min= -99999;
					
					if(0> para_self.ana_out_v_min)
						sprintf(tmp6,"-%05d", -1*para_self.ana_out_v_min);
					else
						sprintf(tmp6,"%06d", para_self.ana_out_v_min);
					seg_updata(tmp6);
						
					set_one_seg_flash(1, SEG_FLASH);
					set_one_seg_point(3, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
					
					sta= 1;
				}
				else{
					seg_updata("------");
					//不进行sta切换。
				}
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}					
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				seg_flash_all(0);
				set_one_seg_point(3, 0);
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
			
		case 1:
			//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
			if(KEY_K1_ESC == key){
				seg_flash_all(0);
				set_one_seg_point(3, 0);
				seg_updata(cur_item->content);
				
				sta= 0;
			}
			else if(key == KEY_K2_OPT){
				if(ANA_V_DEF == para_self.ana_out_mode){
					if(1 == idx_seg){
						//切换0和'-'，即±。
						sign_one_seg(1);
					}
					else{
						inc_one_seg(idx_seg);
					}	
				}
				else
					inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint32_t tmp32;
				int32_t itmp32;
				
				seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8[1~6]。
				tmp8[0]= ' ';
				tmp8[7]= '\0';
				int32_t x= atoi(tmp8);
				
				if(ANA_I_DEF == para_self.ana_out_mode){
					tmp32= para_self.ana_out_min;
					para_self.ana_out_min= (uint32_t)x;

					if(0 != ana_i_para_valid()){
						//恢复原值
						para_self.ana_out_min= tmp32;
						
						seg_updata("ErrorF");
						osDelay(1000);
						break;
					}
					else{
						//合理
					}
						
				}
				else{	//V_OUT
					itmp32= para_self.ana_out_v_min;
					para_self.ana_out_v_min= x;
					
					if(0 != ana_v_para_valid()){
						//恢复原值。
						para_self.ana_out_v_min= itmp32;
						
						seg_flash_all(0);
						seg_updata("ErrorF");
						osDelay(1000);
						
						break;
					}
					else{
						//合理
					}
				}
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.ana_out(_v)_min");

					//update_ana_out_ic_mode();	//更新二次参数，不必在这里更新，应在Thread_DAC()中统一更新。
					
					flag_para_update_dac= 1;	//设置标志，以在Thread_DAC()中修改。
					
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					//保存失败，恢复旧值（断电完蛋）。
					if(ANA_I_DEF == para_self.ana_out_mode)
						para_self.ana_out_min= tmp32;
					else
						para_self.ana_out_v_min= itmp32;
						
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.ana_out(_v)_min");
					osDelay(1000);
				}
			}
			
			break;
		
		default:
			break;
	}		
}





/*SETUP菜单下F33叶子菜单处理函数：（模拟量输出）零点输出。
类比F32
*/
void setup_F33_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	char tmp8[8];
	uint16_t key;	
	
	uint32_t* p;	
	int32_t* pi;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
		
	
	switch (sta){
		case 0:	
			if(KEY_K4_ENTER == key){
				//进入最大量程设置，并显示“100000”。!!不读取当前量程。
				if(ANA_I_DEF == para_self.ana_out_mode){
					if(999999< para_self.ana_out_zero)
						para_self.ana_out_zero= 999999;
					
					sprintf(tmp6,"%06d", para_self.ana_out_zero);	//
					seg_updata(tmp6);
						
					set_one_seg_flash(1, SEG_FLASH);
					set_one_seg_point(3, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
					
					sta= 1;
				}
				else if(ANA_V_DEF == para_self.ana_out_mode){
					if(999999< para_self.ana_out_v_zero)
						para_self.ana_out_v_zero= 999999;
					
					if(para_self.ana_out_v_zero< -99999)
						para_self.ana_out_v_zero= -99999;
					
					if(0> para_self.ana_out_v_zero)
						sprintf(tmp6,"-%05d", -1*para_self.ana_out_v_zero);
					else
						sprintf(tmp6,"%06d", para_self.ana_out_v_zero);
					seg_updata(tmp6);
						
					set_one_seg_flash(1, SEG_FLASH);
					set_one_seg_point(3, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
					
					sta= 1;
				}
				else{
					seg_updata("------");
					//不进行sta切换。
				}
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}					
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				seg_flash_all(0);
				set_one_seg_point(3, 0);
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
			
		case 1:
			//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
			if(KEY_K1_ESC == key){
				seg_flash_all(0);
				set_one_seg_point(3, 0);
				seg_updata(cur_item->content);
				
				sta= 0;
			}
			else if(key == KEY_K2_OPT){
				if(ANA_V_DEF == para_self.ana_out_mode){
					if(1 == idx_seg){
						//切换0和'-'，即±。
						sign_one_seg(1);
					}
					else{
						inc_one_seg(idx_seg);
					}	
				}
				else
					inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint32_t tmp32;
				int32_t itmp32;
				
				seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8[1~6]。
				tmp8[0]= ' ';
				tmp8[7]= '\0';
				int32_t x= atoi(tmp8);
				
				if(ANA_I_DEF == para_self.ana_out_mode){
					tmp32= para_self.ana_out_zero;
					para_self.ana_out_zero= (uint32_t)x;

					if(0 != ana_i_para_valid()){
						//恢复原值
						para_self.ana_out_zero= tmp32;
						
						seg_flash_all(0);
						seg_updata("ErrorF");
						osDelay(1000);
						
						break;
					}
					else{
						//合理
					}
						
				}
				else{	//V_OUT
					itmp32= para_self.ana_out_v_zero;
					para_self.ana_out_v_zero= x;
					
					if(0 != ana_v_para_valid()){
						//恢复原值。
						para_self.ana_out_v_zero= itmp32;
						
						seg_flash_all(0);
						seg_updata("ErrorF");
						osDelay(1000);
						break;
					}
					else{
						//合理
					}
				}
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.ana_out(_v)_zero");

					//update_ana_out_ic_mode();	//更新二次参数，不必在这里更新，应在Thread_DAC()中统一更新。
					
					flag_para_update_dac= 1;	//设置标志，以在Thread_DAC()中修改。
					
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					//保存失败，恢复旧值（断电完蛋）。
					if(ANA_I_DEF == para_self.ana_out_mode)
						para_self.ana_out_zero= tmp32;
					else
						para_self.ana_out_v_zero= itmp32;
						
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.ana_out(_v)_zero");
					osDelay(1000);
				}
			}
			
			break;
		
		default:
			break;
	}
}



/*SETUP菜单下F34叶子菜单处理函数：（模拟量输出）最大量程输出。
类比F32
*/
void setup_F34_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	char tmp8[8];
	uint16_t key;	
	
	uint32_t* p;	
	int32_t* pi;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
		
	
	switch (sta){
		case 0:	
			if(KEY_K4_ENTER == key){
				//进入最大量程设置，并显示“100000”。!!不读取当前量程。
				if(ANA_I_DEF == para_self.ana_out_mode){
					if(999999< para_self.ana_out_cp)
						para_self.ana_out_cp= 999999;
					
					sprintf(tmp6,"%06d", para_self.ana_out_cp);	//
					seg_updata(tmp6);
						
					set_one_seg_flash(1, SEG_FLASH);
					set_one_seg_point(3, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
					
					sta= 1;
				}
				else if(ANA_V_DEF == para_self.ana_out_mode){
					if(999999< para_self.ana_out_v_cp)
						para_self.ana_out_v_cp= 999999;
					
					if(para_self.ana_out_v_cp< -99999)
						para_self.ana_out_v_cp= -99999;
					
					if(0> para_self.ana_out_v_cp)
						sprintf(tmp6,"-%05d", -1*para_self.ana_out_v_cp);
					else
						sprintf(tmp6,"%06d", para_self.ana_out_v_cp);
					seg_updata(tmp6);
						
					set_one_seg_flash(1, SEG_FLASH);
					set_one_seg_point(3, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
					
					sta= 1;
				}
				else{
					seg_updata("------");
					//不进行sta切换。
				}
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}					
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				seg_flash_all(0);
				set_one_seg_point(3, 0);
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
			
		case 1:
			//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
			if(KEY_K1_ESC == key){
				seg_flash_all(0);
				set_one_seg_point(3, 0);
				seg_updata(cur_item->content);
				
				sta= 0;
			}
			else if(key == KEY_K2_OPT){
				if(ANA_V_DEF == para_self.ana_out_mode){
					if(1 == idx_seg){
						//切换0和'-'，即±。
						sign_one_seg(1);
					}
					else{
						inc_one_seg(idx_seg);
					}	
				}
				else
					inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint32_t tmp32;
				int32_t itmp32;
				
				seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8[1~6]。
				tmp8[0]= ' ';
				tmp8[7]= '\0';
				int32_t x= atoi(tmp8);
				
				if(ANA_I_DEF == para_self.ana_out_mode){
					tmp32= para_self.ana_out_cp;
					para_self.ana_out_cp= (uint32_t)x;

					if(0 != ana_i_para_valid()){
						//恢复原值
						para_self.ana_out_cp= tmp32;
						
						seg_flash_all(0);
						seg_updata("ErrorF");
						osDelay(1000);
						
						break;
					}
					else{
						//合理
					}
						
				}
				else{	//V_OUT
					itmp32= para_self.ana_out_v_cp;
					para_self.ana_out_v_cp= x;
					
					if(0 != ana_v_para_valid()){
						//恢复原值。
						para_self.ana_out_v_cp= itmp32;
						
						seg_flash_all(0);
						seg_updata("ErrorF");
						osDelay(1000);
						break;
					}
					else{
						//合理
					}
				}
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.ana_out(_v)_cp");

					//update_ana_out_ic_mode();	//更新二次参数，不必在这里更新，应在Thread_DAC()中统一更新。
					
					flag_para_update_dac= 1;	//设置标志，以在Thread_DAC()中修改。
					
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					//保存失败，恢复旧值（断电完蛋）。
					if(ANA_I_DEF == para_self.ana_out_mode)
						para_self.ana_out_cp= tmp32;
					else
						para_self.ana_out_v_cp= itmp32;
						
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.ana_out(_v)_cp");
					osDelay(1000);
				}
			}
			
			break;
		
		default:
			break;
	}		
}


/*SETUP菜单下F35叶子菜单处理函数：（模拟量输出）最大输出。
类比F32
*/
void setup_F35_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	char tmp8[8];
	uint16_t key;	
	
	uint32_t* p;	
	int32_t* pi;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
		
	
	switch (sta){
		case 0:	
			if(KEY_K4_ENTER == key){
				//进入最大量程设置，并显示“100000”。!!不读取当前量程。
				if(ANA_I_DEF == para_self.ana_out_mode){
					if(999999< para_self.ana_out_max)
						para_self.ana_out_max= 999999;
					
					sprintf(tmp6,"%06d", para_self.ana_out_max);	//
					seg_updata(tmp6);
						
					set_one_seg_flash(1, SEG_FLASH);
					set_one_seg_point(3, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
					
					sta= 1;
				}
				else if(ANA_V_DEF == para_self.ana_out_mode){
					if(999999< para_self.ana_out_v_max)
						para_self.ana_out_v_max= 999999;
					
					if(para_self.ana_out_v_max< -99999)
						para_self.ana_out_v_max= -99999;
					
					if(0> para_self.ana_out_v_max)
						sprintf(tmp6,"-%05d", -1*para_self.ana_out_v_max);
					else
						sprintf(tmp6,"%06d", para_self.ana_out_v_max);
					seg_updata(tmp6);
						
					set_one_seg_flash(1, SEG_FLASH);
					set_one_seg_point(3, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
					
					sta= 1;
				}
				else{
					seg_updata("------");
					//不进行sta切换。
				}
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}					
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				seg_flash_all(0);
				set_one_seg_point(3, 0);
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
			
		case 1:
			//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
			if(KEY_K1_ESC == key){
				seg_flash_all(0);
				set_one_seg_point(3, 0);
				seg_updata(cur_item->content);
				
				sta= 0;
			}
			else if(key == KEY_K2_OPT){
				if(ANA_V_DEF == para_self.ana_out_mode){
					if(1 == idx_seg){
						//切换0和'-'，即±。
						sign_one_seg(1);
					}
					else{
						inc_one_seg(idx_seg);
					}	
				}
				else
					inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint32_t tmp32;
				int32_t itmp32;
				
				seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8[1~6]。
				tmp8[0]= ' ';
				tmp8[7]= '\0';
				int32_t x= atoi(tmp8);
				
				if(ANA_I_DEF == para_self.ana_out_mode){
					tmp32= para_self.ana_out_max;
					para_self.ana_out_max= (uint32_t)x;

					if(0 != ana_i_para_valid()){
						//恢复原值
						para_self.ana_out_max= tmp32;
						
						seg_flash_all(0);
						seg_updata("ErrorF");
						osDelay(1000);
						
						break;
					}
					else{
						//合理
					}
						
				}
				else{	//V_OUT
					itmp32= para_self.ana_out_v_max;
					para_self.ana_out_v_max= x;
					
					if(0 != ana_v_para_valid()){
						//恢复原值。
						para_self.ana_out_v_max= itmp32;
						
						seg_flash_all(0);
						seg_updata("ErrorF");
						osDelay(1000);
						break;
					}
					else{
						//合理
					}
				}
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.ana_out(_v)_max");

					//update_ana_out_ic_mode();	//更新二次参数，不必在这里更新，应在Thread_DAC()中统一更新。
					
					flag_para_update_dac= 1;	//设置标志，以在Thread_DAC()中修改。
					
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					//保存失败，恢复旧值（断电完蛋）。
					if(ANA_I_DEF == para_self.ana_out_mode)
						para_self.ana_out_max= tmp32;
					else
						para_self.ana_out_v_max= itmp32;
						
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.ana_out(_v)_max");
					osDelay(1000);
				}
			}
			
			break;
		
		default:
			break;
	}		
}





/*SETUP菜单下F41叶子菜单处理函数：参数密码设置开关（on/oFF）。
*/
void setup_F41_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	uint16_t key;	
	static uint16_t val_change;	
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			//当前显示“PASS”，等待按enter.
			if(KEY_K4_ENTER == key){
				//根据pwd_setup_sw的值显示
				if(para_self.pwd_setup_sw){
					seg_updata("    on ");
				}
				else{
					seg_updata("   off ");
				}	
				
				val_change= para_self.pwd_setup_sw;
				
				seg_flash_all(1);
//				set_one_seg_flash(4, SEG_FLASH);
//				set_one_seg_flash(5, SEG_FLASH);
//				set_one_seg_flash(6, SEG_FLASH);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;	
		
		case 1:
			//第1次调整密码并确认。
			if(key == KEY_K2_OPT){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(key == KEY_K3_MODE){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t tmp16= para_self.pwd_setup_sw;
				para_self.pwd_setup_sw= val_change;

				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.pwd_setup_sw");
								
					sta= 0;
					seg_flash_all(0);
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);
				}
				else{
					para_self.pwd_setup_sw= tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save pwd_setup_sw");
					osDelay(1000);
				}
			}
			else if( KEY_K1_ESC == key ){
				
				//退出时返回sta= 0
				seg_copy_to_tmp(pass1);
				
				
				sta= 0;
				seg_flash(0);
				
				seg_updata(cur_item->content);
			}
			break;
			
		default:
			break;
	}
}

/*SETUP菜单下F42叶子菜单处理函数：参数密码设置。

*/
void setup_F42_leaf_Fn(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			//当前显示“PASS”，等待按enter.
			if(KEY_K4_ENTER == key){
				//显示"0----- ",并第1个数码管闪。
				seg_updata("0----- ");
				set_one_seg_flash(idx_seg, SEG_FLASH);
				
				sta= 1;
				idx_seg= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
			
		case 1:
			//第1次调整密码并确认。
			if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				seg_copy_to_tmp(tmp);
				
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				if(('-' == tmp[idx_seg]) || ('=' == tmp[idx_seg]))
					set_one_seg(idx_seg,'0', 0);
			}
			else if(key == KEY_K4_ENTER){
				
				seg_copy_to_tmp(pass1);
				
				seg_updata("0===== ");
				seg_flash(0);
				idx_seg=1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				sta= 2;
			}
			else if(key == KEY_K1_ESC){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				
				sta= 0;
				seg_flash_all(0);
			}
			
			break;
			
		case 2:
			//第2次调整密码并确认。
			if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				seg_copy_to_tmp(tmp);
				
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				if(('-' == tmp[idx_seg]) || ('=' == tmp[idx_seg]))
					set_one_seg(idx_seg,'0', 0);
			}
			else if(key == KEY_K4_ENTER){
				
				seg_copy_to_tmp(tmp6);
				
				if(0 != pass_compare2(pass1, tmp6)){
					//2次密码不相同：显示错误后，重新开始。
					seg_updata("Error ");	//测试序列：PASS
					osDelay(2000);
					
					seg_updata("0----- ");
					seg_flash(0);
					idx_seg= 1;
					set_one_seg_flash(idx_seg, SEG_FLASH);
					
					sta= 1;
				}
				else{						
					//保存旧值。
					uint8_t val_tmp8[6];
					for(uint8_t i= 0; i< 6; i++){
						val_tmp8[i]= para_self.pwd_setup[i];
						para_self.pwd_setup[i]= tmp6[i+1];
					}

				
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
						uartS("\nsave para_self.pwd_setup");
				
						//设置密码ok
						seg_updata("SUCC ");
						osDelay(1000);
						
						idx_seg= 1;
						sta= 0;
						seg_flash_all(0);
							
						//cur_item= cur_item->parent;
						seg_updata(cur_item->content);;
					}
					else{
						for(uint8_t i= 0; i< 6; i++){
							para_self.pwd_setup[i]= val_tmp8[i];		//保存失败，恢复旧值（断电完蛋）。
						}
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						uartS("\nerr save para_self.pwd_setup");
						osDelay(1000);
					}
				}
			}
			break;
			
		default:
			break;
	}	
}




/*SPOINT菜单下P11叶子菜单处理函数：状态变化是否需要稳定。
0	oFF
1	on
P11和P21，P31，P41功能相同，已实现统一。
*/
static void leaf_Fn_spoint_P11(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	uint16_t key;
	uint16_t* p_stab;
	static uint16_t val_change;
	
	if(11 == cur_item->id)
		p_stab= &para_xxx.preset_p1_need_stab;
	else if(21== cur_item->id)
		p_stab= &para_xxx.preset_p2_need_stab;
	else if(31== cur_item->id)
		p_stab= &para_xxx.preset_p3_need_stab;
	else if(41== cur_item->id)
		p_stab= &para_xxx.preset_p4_need_stab;
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			//当前显示“PASS”，等待按enter.
			if(KEY_K4_ENTER == key){
				//根据pwd_setup_sw的值显示
				if(*p_stab){
					seg_updata("    on ");
				}
				else{
					seg_updata("   off ");
				}	
				val_change= *p_stab;
				
				set_one_seg_flash(4, SEG_FLASH);
				set_one_seg_flash(5, SEG_FLASH);
				set_one_seg_flash(6, SEG_FLASH);
				//set_one_seg_point(2, 1);	//显示F4.1（不是F41）
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				
				seg_flash(0);
			}
			
			break;	
		
		case 1:
			//第1次调整密码并确认。
			if(key == KEY_K2_OPT){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(key == KEY_K3_MODE){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t val_tmp16= *p_stab;
				*p_stab= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					if(11 == cur_item->id){
						uartS("\nsav preset_p1_need_stab");
					}
					else if(21== cur_item->id){
						uartS("\nsav preset_p2_need_stab");
					}
					else if(31== cur_item->id){
						uartS("\nsav preset_p3_need_stab");
					}
					else if(41== cur_item->id){
						uartS("\nsav preset_p4_need_stab");
					}
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					*p_stab= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					if(11 == cur_item->id)
						uartS("\nerr sav preset_p1_need_stab");
					else if(21== cur_item->id)
						uartS("\nerr sav preset_p2_need_stab");
					else if(31== cur_item->id)
						uartS("\nerr sav preset_p3_need_stab");
					else if(41== cur_item->id)
						uartS("\nerr sav preset_p4_need_stab");
					
					osDelay(1000);
				}
			}
			else if( KEY_K1_ESC == key ){	
				if(11 == cur_item->id)
					uartS("\nesc preset_p1_need_stab");
				else if(21== cur_item->id)
					uartS("\nesc preset_p2_need_stab");
				else if(31== cur_item->id)
					uartS("\nesc preset_p3_need_stab");
				else if(41== cur_item->id)
					uartS("\nesc preset_p4_need_stab");	
				
				seg_updata(cur_item->content);
				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}	
}



/*SPOINT菜单下P12叶子菜单处理函数：状态变化最小持续时间。
有效范围：00.0~99.9。
P11和P21，P31，P41功能相同，已实现统一。
*/
static void leaf_Fn_spoint_P12(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;			//有效范围：1~6
	static uint8_t cnt_pass_err= 0;		//密码错误次数，但4次时锁定（只能关电）。
	static char tmp8[8];				//有效范围：1~6.	
	uint16_t key;
	static uint16_t tmp_duration_min;

	uint16_t* p_duration;
	
	if(12 == cur_item->id)
		p_duration= &para_xxx.preset_p1_duration_min;
	else if(22== cur_item->id)
		p_duration= &para_xxx.preset_p2_duration_min;
	else if(32== cur_item->id)
		p_duration= &para_xxx.preset_p3_duration_min;
	else if(42== cur_item->id)
		p_duration= &para_xxx.preset_p4_duration_min;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(key == KEY_K4_ENTER){
				//显示当前的持续时间。
				if(999< *p_duration)
					*p_duration= 0;
				
				tmp_duration_min= *p_duration;
				show_duration(tmp_duration_min, tmp8);	//show_val(tmp_duration_min, tmp8);
				seg_updata(tmp8);
				set_one_seg_point(5, 1);				//QQ有问题（显示"00.1"，不是"0.1"）：只显示小数点。固定小数点位置。
				
				idx_seg= 6;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				
				seg_flash(0);
			}
			
			break;
		case 1:
			//输入密码：按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
			if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 4;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t val_tmp16= *p_duration;
				seg_copy_to_tmp(tmp8);
				tmp8[0]= ' ';
				tmp8[7]= '\0';
				
				*p_duration= atoi(tmp8);
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					if(11 == cur_item->id)
						uartS("\nerr sav preset_p1_need_stab");
					else if(21== cur_item->id)
						uartS("\nerr sav preset_p2_need_stab");
					else if(31== cur_item->id)
						uartS("\nerr sav preset_p3_need_stab");
					else if(41== cur_item->id)
						uartS("\nerr sav preset_p4_need_stab");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					*p_duration= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					if(12 == cur_item->id)
						uartS("\nerr sav preset_p1_duration_min");
					else if(22== cur_item->id)
						uartS("\nerr sav preset_p2_duration_min");
					else if(32== cur_item->id)
						uartS("\nerr sav preset_p3_duration_min");
					else if(42== cur_item->id)
						uartS("\nerr sav preset_p4_duration_min");
					
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				if(12 == cur_item->id)
					uartS("\nesc preset_p1_duration_min");
				else if(22== cur_item->id)
					uartS("\nesc preset_p2_duration_min");
				else if(32== cur_item->id)
					uartS("\nesc preset_p3_duration_min");
				else if(42== cur_item->id)
					uartS("\nesc preset_p4_duration_min");	
				
				seg_updata(cur_item->content);
				sta= 0;
				seg_flash(0);
			}
			
			break;
		default:
			break;
	}
}	


/*SPOINT菜单下P13叶子菜单处理函数：有效条件（范围：0~9）。
0：禁止；
1：<小于
2：<=小于等于
3：==等于
4：>=大于等于
5：>大于
6：!=不等于；跟最小值比较
7：_<>_区间外，需要设置两个边界值
8：=<__>=区间内，需要设置两个边界值
9： 高限值（外部触发（作废））
10：低限值
P11和P21，P31，P41功能相同，已实现统一。
*/
static void leaf_Fn_spoint_P13(MSG_U msg)
{
	static uint8_t sta= 0;
	char tmp8[8];
	static uint8_t val_change;
	uint16_t key;
	uint16_t* p_cond;
	
	if(13 == cur_item->id)
		p_cond= &para_xxx.preset_p1_condition;
	else if(23== cur_item->id)
		p_cond= &para_xxx.preset_p2_condition;
	else if(33== cur_item->id)
		p_cond= &para_xxx.preset_p3_condition;
	else if(43== cur_item->id)
		p_cond= &para_xxx.preset_p4_condition;
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(9< *p_cond)
					*p_cond= 0;
				
				val_change= *p_cond;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc preset_p1_condition");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				seg_flash(0);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(10<= val_change)
					val_change= 0;
				else
					val_change++;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				
				if(0 ==  val_change)
					val_change= 10;
				else
					val_change--;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= *p_cond;
				*p_cond= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					if(13 == cur_item->id){
						preset_point[1].sta_pre= 0;
						preset_point[1].ts_valid_start_valid= 0;
						preset_point[1].ts_invalid_start_valid= 0;
						preset_point[1].flag_wait_unsatisfy= 0;
						
						uartS("\nsave preset_p1_condition");
					}
					else if(23== cur_item->id){
						preset_point[2].sta_pre= 0;
						preset_point[2].ts_valid_start_valid= 0;
						preset_point[2].ts_invalid_start_valid= 0;
						preset_point[2].flag_wait_unsatisfy= 0;
						
						uartS("\nsave preset_p2_condition");
					}
					else if(33== cur_item->id){
						preset_point[3].sta_pre= 0;
						preset_point[3].ts_valid_start_valid= 0;
						preset_point[3].ts_invalid_start_valid= 0;
						preset_point[3].flag_wait_unsatisfy= 0;
						
						uartS("\nsave preset_p3_condition");
					}
					else if(43== cur_item->id){
						preset_point[4].sta_pre= 0;
						preset_point[4].ts_valid_start_valid= 0;
						preset_point[4].ts_invalid_start_valid= 0;
						preset_point[4].flag_wait_unsatisfy= 0;
						
						uartS("\nsave preset_p4_condition");
					}
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					*p_cond= val_tmp16;			//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					if(13 == cur_item->id)
						uartS("\nerr save preset_p1_condition");
					else if(23== cur_item->id)
						uartS("\nerr save preset_p2_condition");
					else if(33== cur_item->id)
						uartS("\nerr save preset_p3_condition");
					else if(43== cur_item->id)
						uartS("\nerr save preset_p4_condition");
					
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				if(13 == cur_item->id)
					uartS("\nesc preset_p1_condition");
				else if(23== cur_item->id)
					uartS("\nesc preset_p2_condition");
				else if(33== cur_item->id)
					uartS("\nesc preset_p3_condition");
				else if(43== cur_item->id)
					uartS("\nesc preset_p4_condition");
				
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}			
}



/*SPOINT菜单下P14叶子菜单处理函数：设置设定值1（范围：-99999~99999）。

P11和P21，P31，P41功能相同，已实现统一。
*/
static void leaf_Fn_spoint_P14(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;			//有效范围：1~6
	static uint8_t cnt_pass_err= 0;		//密码错误次数，但4次时锁定（只能关电）。
	static char tmp8[8];				//有效范围：1~6.	
	uint16_t key;
	static int32_t itmp_val;	
	uint32_t tmp32;
	
	uint16_t* p_val_hi;
	uint16_t* p_val_lo;
	
	if(14 == cur_item->id){
		p_val_hi= &para_xxx.preset_p1_val_1_hi;
		p_val_lo= &para_xxx.preset_p1_val_1_lo;
	}
	else if(24== cur_item->id){
		p_val_hi= &para_xxx.preset_p2_val_1_hi;
		p_val_lo= &para_xxx.preset_p2_val_1_lo;
	}
	else if(34== cur_item->id){
		p_val_hi= &para_xxx.preset_p3_val_1_hi;
		p_val_lo= &para_xxx.preset_p3_val_1_lo;
	}
	else if(44== cur_item->id){
		p_val_hi= &para_xxx.preset_p4_val_1_hi;
		p_val_lo= &para_xxx.preset_p4_val_1_lo;
	}
	
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//显示当前的持续时间。
				tmp32= *p_val_hi;
				tmp32<<= 16;
				tmp32|= *p_val_lo;
				
				itmp_val= (int32_t)tmp32;
				
				if(99999< itmp_val)
					itmp_val= 0;
				
				
				sprintf(tmp8, "%06d", itmp_val);	//show_val(itmp_val, tmp8);
				seg_updata(tmp8);
				
				idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				seg_flash(0);
			}
			
			break;
		case 1:
			//输入密码：按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
			if(key == KEY_K2_OPT){
				if(1 == idx_seg){
					//变为'-'负号
					sign_one_seg(1);
				}
				else
					inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t val_tmp16= *p_val_hi;
				uint16_t val_tmp16_2= *p_val_lo;
				
				seg_copy_to_tmp(tmp8);
				tmp8[0]= ' ';
				tmp8[7]= '\0';
				
				itmp_val= atoi(tmp8);//(int32_t)tmp32;
				tmp32= (uint32_t)itmp_val;
				*p_val_hi= tmp32>> 16;
				*p_val_lo= (uint16_t)tmp32;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					if(14 == cur_item->id)
						uartS("\nsav preset_p1_val_1");
					else if(24== cur_item->id)
						uartS("\nsav preset_p2_val_1");
					else if(34== cur_item->id)
						uartS("\nsav preset_p3_val_1");
					else if(44== cur_item->id)
						uartS("\nsav preset_p4_val_1");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					*p_val_hi= val_tmp16;			//保存失败，恢复旧值（断电完蛋）。
					*p_val_lo=val_tmp16_2;
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					if(14 == cur_item->id)
						uartS("\nerr sav preset_p1_val_1");
					else if(24== cur_item->id)
						uartS("\nerr sav preset_p2_val_1");
					else if(34== cur_item->id)
						uartS("\nerr sav preset_p3_val_1");
					else if(44== cur_item->id)
						uartS("\nerr sav preset_p4_val_1");
					
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				if(14 == cur_item->id)
					uartS("\nesc preset_p1_val_1");
				else if(24== cur_item->id)
					uartS("\nesc preset_p2_val_1");
				else if(34== cur_item->id)
					uartS("\nesc preset_p3_val_1");
				else if(44== cur_item->id)
					uartS("\nesc preset_p4_val_1");
				
				seg_updata(cur_item->content);
				sta= 0;
				seg_flash(0);
			}
			
			break;
		default:
			break;
	}
}	



/*SPOINT菜单下P15叶子菜单处理函数：设置设定值1（范围：-99999~99999）。
0	oFF
1	on
P11和P21，P31，P41功能相同，已实现统一。
*/
static void leaf_Fn_spoint_P15(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;			//有效范围：1~6
	static uint8_t cnt_pass_err= 0;		//密码错误次数，但4次时锁定（只能关电）。
	static char tmp8[8];				//有效范围：1~6.	
	uint16_t key;
	static int32_t itmp_val;	
	uint32_t tmp32;
	
	uint16_t* p_val_hi;
	uint16_t* p_val_lo;
	
	if(15 == cur_item->id){
		p_val_hi= &para_xxx.preset_p1_val_2_hi;
		p_val_lo= &para_xxx.preset_p1_val_2_lo;
	}
	else if(25== cur_item->id){
		p_val_hi= &para_xxx.preset_p2_val_2_hi;
		p_val_lo= &para_xxx.preset_p2_val_2_lo;
	}
	else if(35== cur_item->id){
		p_val_hi= &para_xxx.preset_p3_val_2_hi;
		p_val_lo= &para_xxx.preset_p3_val_2_lo;
	}
	else if(45== cur_item->id){
		p_val_hi= &para_xxx.preset_p4_val_2_hi;
		p_val_lo= &para_xxx.preset_p4_val_2_lo;
	}
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//显示当前的持续时间。
				tmp32= *p_val_hi;
				tmp32<<= 16;
				tmp32|= *p_val_lo;
				
				itmp_val= (int32_t)tmp32;
				
				if(99999< itmp_val)
					itmp_val= 0;
				
				
				sprintf(tmp8, "%06d", itmp_val);	//show_val(itmp_val, tmp8);
				seg_updata(tmp8);
				
				idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				seg_flash(0);
			}
			
			break;
		case 1:
			//输入密码：按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
			if(key == KEY_K2_OPT){
				if(1 == idx_seg){
					//变为'-'负号
					sign_one_seg(1);
				}
				else
					inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t val_tmp16= *p_val_hi;
				uint16_t val_tmp16_2= *p_val_lo;
				
				seg_copy_to_tmp(tmp8);
				tmp8[0]= ' ';
				tmp8[7]= '\0';
				
				itmp_val= atoi(tmp8);//(int32_t)tmp32;
				tmp32= (uint32_t)itmp_val;
				*p_val_hi= tmp32>> 16;
				*p_val_lo= (uint16_t)tmp32;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					if(14 == cur_item->id)
						uartS("\nsav preset_p1_val_2");
					else if(24== cur_item->id)
						uartS("\nsav preset_p2_val_2");
					else if(34== cur_item->id)
						uartS("\nsav preset_p3_val_2");
					else if(44== cur_item->id)
						uartS("\nsav preset_p4_val_2");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					*p_val_hi= val_tmp16;			//保存失败，恢复旧值（断电完蛋）。
					*p_val_lo=val_tmp16_2;
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					if(14 == cur_item->id)
						uartS("\nerr sav preset_p1_val_2");
					else if(24== cur_item->id)
						uartS("\nerr sav preset_p2_val_2");
					else if(34== cur_item->id)
						uartS("\nerr sav preset_p3_val_2");
					else if(44== cur_item->id)
						uartS("\nerr sav preset_p4_val_2");
					
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				if(15 == cur_item->id)
					uartS("\nesc preset_p1_val_2");
				else if(25== cur_item->id)
					uartS("\nesc preset_p2_val_2");
				else if(35== cur_item->id)
					uartS("\nesc preset_p3_val_2");
				else if(45== cur_item->id)
					uartS("\nesc preset_p4_val_2");
				
				seg_updata(cur_item->content);
				sta= 0;
				seg_flash(0);
			}
			
			break;
		default:
			break;
	}
}	



/*HOLD菜单下H1叶子菜单处理函数：设置保持模式（范围：0~4）。
0	无保持功能
1	峰值保持
2	谷值保持
3	峰-谷值保持
4	采样值保持
*/
static void leaf_Fn_hold_H1(MSG_U msg)
{
	static uint8_t sta= 0;
	char tmp8[8];
	static uint8_t val_change;
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(4< para_xxx.hold_mode)
					para_xxx.hold_mode= 0;
				
				val_change= para_xxx.hold_mode;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc hold_mode");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(4<= val_change)
					val_change= 0;
				else
					val_change++;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				
				if(0 ==  val_change)
					val_change= 4;
				else
					val_change--;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.hold_mode;	
				para_xxx.hold_mode= val_change;	
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave hold_mode");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.hold_mode= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save hold_mode");
					
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc hold_mode");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}
}



/*HOLD菜单下H1叶子菜单处理函数：设置保持触发条件（范围：0~1）。
0	外部触发（由开关量输入或外部命令触发有效）
1	零区触发（仅针对峰值保持和谷值保持有效）
*/
static void leaf_Fn_hold_H2(MSG_U msg)
{
	static uint8_t sta= 0;
	char tmp8[8];
	static uint8_t val_change;
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(1< para_xxx.triger_conditon)
					para_xxx.triger_conditon= 0;
				
				val_change= para_xxx.triger_conditon;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc hold_mode");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(1<= val_change)
					val_change= 0;
				else
					val_change++;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				
				if(0 ==  val_change)
					val_change= 1;
				else
					val_change--;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.triger_conditon;
				para_xxx.triger_conditon= val_change;	
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave triger_conditon");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.triger_conditon= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save triger_conditon");
					
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc triger_conditon");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}
}


/*HOLD菜单下H1叶子菜单处理函数：零区值（H2 为零区触发时有效）（范围：0~999999）。
零区值（H2 为零区触发时有效，峰值保持时，显示值超过零
区则启动保持，谷值保持时，显示值低于负零区值时启动保持，
显示值回到零区后，保持结束，仪表保存该值至下一次保持启
动，过程中可按 切换显示状态）
*/
static void leaf_Fn_hold_H3(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static uint8_t cnt_pass_err= 0;	//密码错误次数，但4次时锁定（只能关电）。
	static char tmp8[8];		//有效范围：1~6.	
	uint16_t key;
	uint32_t tmp32;
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//显示当前值。
				char str[8];
				tmp32= para_xxx.triger_zero_hi;
				tmp32<<= 16;
				tmp32|= para_xxx.triger_zero_lo;
				if(999999< tmp32){
					para_xxx.triger_zero_hi= 0;
					para_xxx.triger_hold_lo= 0;
					tmp32= 0;
				}
					
				sprintf(str, "%06d", tmp32);
				
				seg_updata(str);	//测试序列：PASS
				//第1个‘0’闪
				idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc hold_mode");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
		case 1:
			//输入密码：按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
			if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				seg_copy_to_tmp(tmp8);
				
				tmp8[0]= ' ';
				tmp8[7]='\0';
				tmp32= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
				
				uint16_t val_tmp16= para_xxx.triger_zero_hi;
				uint16_t val_tmp16_2= para_xxx.triger_zero_lo;
				
				para_xxx.triger_zero_hi= (tmp32>> 16);
				para_xxx.triger_zero_lo= (uint16_t)tmp32;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave triger_zero_hi/lo");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.triger_zero_hi= val_tmp16;			//保存失败，恢复旧值（断电完蛋）。
					para_xxx.triger_zero_lo= val_tmp16_2;
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save triger_zero_hi/lo");
					
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				uartS("\nesc triger_zero_hi/lo");
				
				sta= 0;
				seg_flash(0);
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
		default:
			break;
	}
}



/*OUT1叶子菜单项处理函数。
0	无定义
1	稳定
2	溢出
3	限制1
4	限制2
5	限制3
6	限制4
*/
static void leaf_Fn_io_out1(MSG_U msg){
	static uint8_t sta= 0;
	char tmp8[8];
	static uint8_t val_change;
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(9< para_xxx.out1_define)
					para_xxx.out1_define= 0;
				
				val_change= para_xxx.out1_define;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc out1_define");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(6<= val_change)
					val_change= 0;
				else
					val_change++;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				
				if(0 ==  val_change)
					val_change= 6;
				else
					val_change--;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.out1_define;
				para_xxx.out1_define= val_change;	
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave out1_define");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.out1_define= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save out1_define");
					
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc out1_define");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}			
}	



/*OUT2叶子菜单项处理函数。
0	无定义
1	稳定
2	溢出
3	限制1
4	限制2
5	限制3
6	限制4
*/
static void leaf_Fn_io_out2(MSG_U msg){
	static uint8_t sta= 0;
	char tmp8[8];
	static uint8_t val_change;
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(9< para_xxx.out2_define)
					para_xxx.out2_define= 0;
				
				val_change= para_xxx.out2_define;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc out2_define");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(6<= val_change)
					val_change= 0;
				else
					val_change++;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				
				if(0 ==  val_change)
					val_change= 6;
				else
					val_change--;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.out2_define;
				para_xxx.out2_define= val_change;	
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave out2_define");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.out2_define= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save out2_define");
					
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc out2_define");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}			
}	



/*IN1叶子菜单项处理函数。
0	无定义
1	清零
2	限制1
3	限制2
4	限制3
5	限制4
6	触发保持
7	电平保持
*/
static void leaf_Fn_io_in1(MSG_U msg){
	static uint8_t sta= 0;
	char tmp8[8];
	static uint8_t val_change;
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取零点跟踪范围并闪显。
				if(7< para_xxx.in1_define)
					para_xxx.in1_define= 0;
				
				val_change= para_xxx.in1_define;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
				
				seg_flash(1);
				
				sta= 1;
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				cur_item= cur_item->up_sibble;	
				seg_updata(cur_item->content);
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc in1_define");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//显示值+1。
				if(7<= val_change)
					val_change= 0;
				else
					val_change++;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				
				if(0 ==  val_change)
					val_change= 7;
				else
					val_change--;
				
				show_val(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.in1_define;
				para_xxx.in1_define= val_change;	
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave in1_define");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.in1_define= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save in1_define");
					
					osDelay(1000);
				};
			}
			else if(KEY_K1_ESC == key){
				//不保存当前值，在同级菜单循环切换？
				uartS("\nesc in1_define");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash(0);
			}
			break;
			
		default:
			break;
	}			
}	



/*复位叶子菜单的处理。
不再设置下级菜单：PASS -> F SET -> F CAL -> F ALL -> RST，而是在一个函数中实现。
方法：将出厂值复制到变量，将变量写入FLASH，并设置以下标志，以同步硬件：
		
*/
static void leaf_Fn_rst(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 0;
	char tmp8[8];
	static uint8_t val_change;
	uint16_t key;	
	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			//此时显示“PASS  ”，按确认键跳到输入密码。
			if(KEY_K4_ENTER == key){
				sta= 1;
				seg_updata("000000");	//PASS
				//第1个‘0’闪
				idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
			
		case 1:
			//输入密码：按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
			if(key == KEY_K1_ESC){
				//退出
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				
				seg_flash(0);
				sta= 0;
			}	
			else if(key == KEY_K2_OPT){
				inc_one_seg(idx_seg);
			}
			else if(key == KEY_K3_MODE){
				set_one_seg_flash(idx_seg, SEG_LIGHT);
				
				idx_seg++;
				if(6< idx_seg)
					idx_seg= 1;
				set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(key == KEY_K4_ENTER){
				
				seg_copy_to_tmp(tmp8);
				//比较密码，如果正确，进入下一个邻居菜单。
				if(0UL == pass_compare_rst(tmp8)){
					sta= 2;
					
					seg_updata("F SET");
					uartS("\n to be rst SET");
				}
				else{
					//否则，显示Error为1秒。
					seg_copy_to_tmp(tmp8);
					set_one_seg_flash(idx_seg, SEG_LIGHT);	//关闭闪烁
					

					seg_updata("Error1");

					osDelay(2000);
					seg_updata("000000");	//QQ最好是tmp8，但测试发现tmp8[]从1开始，而非0开始。
					
					idx_seg= 1;
					set_one_seg_flash(idx_seg, SEG_FLASH);
				}
			}
			else{
				//不处理
			}
			
			break;
			
		case 2:
			//显示着"F SET"
			if(key == KEY_K3_MODE){
				//显示下一个，即"F CAL"。
				sta= 3;
					
				seg_updata("F CAL");
				uartS("\n to be rst CAL");
			}
			else if(key == KEY_K2_OPT){
				//显示下一个，即"F ALL"。
				sta= 4;
					
				seg_updata("F ALL");
				uartS("\n to be rst ALL");
			}
			else if(key == KEY_K4_ENTER){
				//执行复位"F_SET"：设置复位标志，并退回上级菜单。
				copy_default_to_set();	//既包含_XXXX，又包含_SELF。需要写2次FLASH。
				
					
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX | FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\n F SET ok");
					
					update_window_size();		//更新二次参数。
					update_stab_size_err();
					update_fs_max();
				
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr F SET");
					
					osDelay(1000);
				}
			}
			else if(key == KEY_K1_ESC){
				//退出
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				
				sta= 0;
			}
			
			break;
			
		case 3:
			//显示着"F CAL"
			if(key == KEY_K3_MODE){
				//显示下一个，即"F ALL"。
				sta= 4;
					
				seg_updata("F ALL");
				uartS("\n to be rst ALL");
			}
			else if(key == KEY_K2_OPT){
				//显示上一个，即"F SET"。
				sta= 2;
					
				seg_updata("F SET");
				uartS("\n to be rst SET");
			}
			else if(key == KEY_K4_ENTER){
				//执行复位"F CAL"：设置复位标志，并退回上级菜单。
				copy_default_to_cal();	//只包含_XXXX。
				
				update_window_size();		//更新二次参数。
				update_stab_size_err();
				update_fs_max();
				
					
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\n F CAL ok");
				
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr F SET");
					
					osDelay(1000);
				}
			}
			else if(key == KEY_K1_ESC){
				//退出
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				
				sta= 0;
			}
				
			break;
			
		case 4:
			//显示着"F ALL"
			if(key == KEY_K3_MODE){
				//显示下一个，即"F SET"。
				sta= 2;
					
				seg_updata("F SET");
				uartS("\n to be rst SET");
			}
			else if(key == KEY_K2_OPT){
				//显示上一个，即"F CAL"。
				sta= 3;
					
				seg_updata("F CAL");
				uartS("\n to be rst CAL");
			}
			else if(key == KEY_K4_ENTER){
				//执行复位"F ALL"：
				copy_default_to_set_cal();
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX | FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\n F ALL ok");
					
					update_window_size();		//更新二次参数。
					update_stab_size_err();
					update_fs_max();
				
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr F ALL");
					
					osDelay(1000);
				}
			}
			else if(key == KEY_K1_ESC){
				//退出
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				
				sta= 0;
			}
			
		default:
			break;
	}			
}



/*校准设置的密码比较。
返回值：0---比较正确。其他---错误。
!!从p[1]~p[6]。
*/
static int32_t pass_compare(char* p)
{	
	if((para_self.pwd_cal[0]< '0') || ('9'< para_self.pwd_cal[0]))
		para_self.pwd_cal[0]= '0';
	
	if((para_self.pwd_cal[1]< '0') || ('9'< para_self.pwd_cal[1]))
		para_self.pwd_cal[1]= '0';
	
	if((para_self.pwd_cal[2]< '0') || ('9'< para_self.pwd_cal[2]))
		para_self.pwd_cal[2]= '0';
	
	if((para_self.pwd_cal[3]< '0') || ('9'< para_self.pwd_cal[3]))
		para_self.pwd_cal[3]= '0';
	
	if((para_self.pwd_cal[4]< '0') || ('9'< para_self.pwd_cal[4]))
		para_self.pwd_cal[4]= '0';
	
	if((para_self.pwd_cal[5]< '0') || ('9'< para_self.pwd_cal[5]))
		para_self.pwd_cal[5]= '0';
	
	
	
	if( (para_self.pwd_cal[0] == p[1]) && (para_self.pwd_cal[1] == p[2]) &&
		(para_self.pwd_cal[2] == p[3]) && (para_self.pwd_cal[3] == p[4]) &&
		(para_self.pwd_cal[4] == p[5]) && (para_self.pwd_cal[5] == p[6]) ){
		return 0;
	}
	else
		return -1;
}



/*参数设置的密码比较。
返回值：0---比较正确。其他---错误。
!!从p[1]~p[6]。
*/
static int32_t pass_setup_compare(char* p)
{	
	if((para_self.pwd_setup[0]< '0') || ('9'< para_self.pwd_setup[0]))
		para_self.pwd_setup[0]= '0';
	
	if((para_self.pwd_setup[1]< '0') || ('9'< para_self.pwd_setup[1]))
		para_self.pwd_setup[1]= '0';
	
	if((para_self.pwd_setup[2]< '0') || ('9'< para_self.pwd_setup[2]))
		para_self.pwd_setup[2]= '0';
	
	if((para_self.pwd_setup[3]< '0') || ('9'< para_self.pwd_setup[3]))
		para_self.pwd_setup[3]= '0';
	
	if((para_self.pwd_setup[4]< '0') || ('9'< para_self.pwd_setup[4]))
		para_self.pwd_setup[4]= '0';
	
	if((para_self.pwd_setup[5]< '0') || ('9'< para_self.pwd_setup[5]))
		para_self.pwd_setup[5]= '0';
	
	
	
	if( (para_self.pwd_setup[0] == p[1]) && (para_self.pwd_setup[1] == p[2]) &&
		(para_self.pwd_setup[2] == p[3]) && (para_self.pwd_setup[3] == p[4]) &&
		(para_self.pwd_setup[4] == p[5]) && (para_self.pwd_setup[5] == p[6]) ){
		return 0;
	}
	else
		return -1;
}



/*比较复位菜单的RST密码是否正确。
返回值：0---比较正确。其他---错误。
!!和固定值比较。“230116”：初版完成时间（即入职3个月）。
*/
static int32_t pass_compare_rst(char* p)
{		
	if( ('2' == p[1]) && ('3' == p[2]) &&
		('0' == p[3]) && ('1' == p[4]) &&
		('1' == p[5]) && ('6' == p[6]) ){
		return 0;
	}
	else
		return -1;
}



static int32_t pass_compare2(char* p1, char* p2)
{
	for(int i=1; i< 7; i++){
		if(p1[i] != p2[i])
			return -1;
	}
	
	return 0;
	
}



/*显示小数点位数，小数点再第1个'0'后。
*/
static void show_pt(uint32_t pos, char* p)
{
	if(1 == pos){
		strcpy(p, "Pt  00 ");
	}
	else if(2 == pos){
		strcpy(p, "Pt 000 ");
	}
	else if(3 == pos){
		strcpy(p, "Pt0000 ");
	}
	else if(4 == pos){
		strcpy(p, "P00000 ");
	}
	else{	//0或其他。
		strcpy(p, "Pt   0 ");
	}
}


static void show_1d(uint32_t dat_1d, char* p)
{
	if(0 == dat_1d){
		strcpy(p, "1d= 01");
	}
	else if(1 == dat_1d){
		strcpy(p, "1d= 02");
	}
	else if(2 == dat_1d){
		strcpy(p, "1d= 05");
	}
	else if(3 == dat_1d){
		strcpy(p, "1d= 10");
	}
	else if(4 == dat_1d){
		strcpy(p, "1d= 20");
	}
	else if(5 == dat_1d){
		strcpy(p, "1d= 50");
	}
	else{	//其他情况按1算。
		strcpy(p, "1d= 01");
	}
}



/*将val转换为字符串后赋值给p。该字符串最大6个字符。
输入参数 val: 待转换的数（int值，可正可负）。
输入参数 p:   输出的字符串指针，!!从p[0]开始。 
例：val=123，则p指向"   123"（共6个字符，右对齐）。
*/
static void show_val(int32_t val, char* p)
{
	char str[8];
	sprintf(str, "%d", val);
	
	
	for(int i= 0;i<7; i++)	//填充为' '。
			p[i]= ' ';
	
	
	uint8_t cnt= strlen(str);	//长度不含'\0'。
	
	if((0 == cnt) || (6< cnt)){
		p[6]= '0';
		p[7]= '\0';
		
		return;
	}
	
	//右对齐到p[5]。
	for(int i= 0; i< cnt; i++){
		p[5-i]= str[cnt-i-1];
	}
}



/*将val转换为字符串后赋值给p。
输入参数 val: 待转换的数（int值，可正可负）。
输入参数 p:   输出的字符串指针，!!从p[0]开始。 
说明：固定字符串长度为3个字节。"00.0~99.9"。
*/
static void show_duration(int32_t val, char* p)
{
	char str[8];
	sprintf(str, "%03d", val);	//固定字符串长度为3个字节
	
	
	for(int i= 0;i<7; i++)
		p[i]= ' ';
	
	//补充上3，4，5
	p[3]= str[0];
	p[4]= str[1];
	p[5]= str[2];
}



/*将val转换为字符串后赋值给p。
输入参数 val: 待转换的数（int值，可正可负）。
输入参数 p:   输出的字符串指针，!!从p[0]开始。 
*/
static void show_val_5(int32_t val, char* p)
{
	char str[8];
	sprintf(str, "%d", val);
	
	
	for(int i= 0;i<7; i++)
			p[i]= ' ';
	
	
	uint8_t cnt= strlen(str);
	
	if((0 == cnt) || (6< cnt)){
		p[6]= '0';
		p[7]= '\0';
		
		return;
	}
	
	//倒序放入p中。
	for(int i= 0; i< cnt; i++){
		p[5-i]= str[cnt-i-1];
	}
}



/*根据序号，显示输出方法字符串。
输入参数 val: 范围0~9.
输入/处参数 p: 转换后的字符串，有效需要从1开始。
0	电流输出4-20
1	电流输出0-20
2	电流0-24
3	电压0-5
4	电压0-10
5	电压-5-5
6	电压-10-10
7	自定义I_out，暂未实现
8	自定义V_out，暂未实现
*/
static void show_output_i_u(uint32_t val, char* p)
{
	if(0 == val){
		strcpy(p, "  4-20");
	}
	else if(1 == val){
		strcpy(p, "  0-20");
	}
	else if(2 == val){
		strcpy(p, "  0-24");
	}
	else if(3 == val){
		strcpy(p, "   0-5");
	}
	else if(4 == val){
		strcpy(p, "  0-10");
	}
	else if(5 == val){
		strcpy(p, "  -5-5");
	}
	else if(6 == val){
		strcpy(p, " -10-10");
	}
	else if(7 == val){
		strcpy(p, "i  out");
	}
	else if(8 == val){
		strcpy(p, "i  out");
	}
	else /*其他*/{
		strcpy(p, "  4-20");
	}
}



/*根据序号，显示波特率字符串。波特率：9600/19200/38400/57600 (任选一种)。
输入参数 val: 范围0~3.
输入/处参数 p: 转换后的字符串，有效需要从1开始。。
*/
static void show_com_baud(uint32_t val, char* p)
{
	if(0 == val){
		strcpy(p, "  9600");
	}
	else if(1 == val){
		strcpy(p, " 19200");
	}
	else if(2 == val){
		strcpy(p, " 38400");
	}
	else if(3 == val){
		strcpy(p, " 57600");
	}
	else /*其他*/{
		strcpy(p, "  9600");
	}
}



/*根据序号，显示通讯模式。
输入参数 val: 范围0~2.
输入/处参数 p: 转换后的字符串，有效需要从0开始。
0	b-rtu
1	Cont
2	rS-SP1
*/
static void show_com_mode(uint32_t val, char* p)
{
	if(0 == val){
		strcpy(p, "   rtu");
	}
	else if(1 == val){
		strcpy(p, "  Cont");
	}
	else if(2 == val){
		strcpy(p, "rs-SP1");
	}
	else /*其他*/{
		strcpy(p, "   rtu");
	}
}



/*准备作废
根据序号，显示有效条件。参考DT45，显示'0'~'9'。
输入参数 val: 范围0~9.
输入/处参数 p: 转换后的字符串，有效需要从1开始。
0：禁止；
1：<小于
2：<=小于等于
3：==等于
4：>=大于等于
5：>大于
6：!=不等于；跟最小值比较
7：_<>_区间外，需要设置两个边界值
8：=<__>=区间内，需要设置两个边界值
9：外部触发
*/
static void show_conditon(uint32_t val, char* p)
{
	if(0 == val){
		strcpy(p, "    dis");
	}
	else if(1 == val){
		strcpy(p, "     lt");
	}
	else if(2 == val){
		strcpy(p, " rs-SP1");
	}
	else /*其他*/{
		strcpy(p, "    rtu");
	}
}



/*根据序号，显示通信格式。
输入参数 val: 范围0~3.
输入/处参数 p: 转换后的字符串，有效需要从0开始。
格式：
0	7-E-1：7位数据位，偶校验，1位停止位；
1	7-O-1：7位数据位，奇校验，1位停止位；
2	8-E-1：8位数据位，偶校验，1位停止位；
3	8-O-1：8位数据位，奇校验，1位停止位；
4	8-n-1：8位数据位，无校验，1位停止位；
5	8-n-2：8位数据位，无校验，2位停止位；
*/
static void show_com_format(uint32_t val, char* p)
{
	if(0 == val){
		strcpy(p, " 7-E-1");
	}
	else if(1 == val){
		strcpy(p, " 7-0-1");
	}
	else if(2 == val){
		strcpy(p, " 8-E-1");
	}
	else if(3 == val){
		strcpy(p, " 8-0-1");
	}
	else if(4 == val){
		strcpy(p, " 8-n-1");
	}
	else if(5 == val){
		strcpy(p, " 8-n-2");
	}
	else{ /*其他或if( 5== val)*/
		strcpy(p, " 8-n-1");
	}
}



/*根据序号，显示Modbus字节序。
输入参数 val: 范围0~1.
输入/处参数 p: 转换后的字符串，有效需要从0开始。
格式：
0	hilo：高字在前低字在后；
1	lohi：低字在前高字在后；
*/
static void show_hilo(uint32_t val, char* p)
{
	if(0 == val){
		strcpy(p, "  hilo");
	}
	else{
		strcpy(p, "  lohi");
	}
}



/*根据序号，显示发送间隔时间。
输入参数 val: 范围0~5.
输入/处参数 p: 转换后的字符串，有效需要从0开始。
格式：
0	none
1	10
2	20
3	30
4	40
5	50
*/
static void show_com_interval(uint32_t val, char* p)
{
	if(0 == val){
		strcpy(p, "  none");
	}
	else if(1 == val){
		strcpy(p, "    10");
	}
	else if(2 == val){
		strcpy(p, "    20");
	}
	else if(3 == val){
		strcpy(p, "    30");
	}
	else if(4 == val){
		strcpy(p, "    40");
	}
	else if(5 == val){
		strcpy(p, "    50");
	}
	else /*其他*/{
		strcpy(p, "  none");
	}
}





static void inc_1d(uint8_t* p)
{
	if(*p == 1){
		*p= 2;
	}
	else if(*p == 2){
		*p= 5;
	}
	else if(*p == 5){
		*p= 10;
	}
	else if(*p == 10){
		*p= 20;
	}
	else if(*p == 20){
		*p= 50;
	}
	else if(*p == 50){	//50或其他
		*p= 1;
	}
	else	//其他按1.
		*p= 1;
}

static void dec_1d(uint8_t* p)
{
	if(*p == 1){
		*p= 50;
	}
	else if(*p == 2){
		*p= 1;
	}
	else if(*p == 5){
		*p= 2;
	}
	else if(*p == 10){
		*p= 5;
	}
	else if(*p == 20){
		*p= 10;
	}
	else if(*p == 50){	//50或其他
		*p= 20;
	}
	else	//其他按1.
		*p= 1;
}



/*在test_io菜单，按下Enter键后的处理函数。
*/
static void enter_Fn_test_io(void)
{
	uartS("\n1-->sw_test_dig_io");
	
	para_coil|= COIL_BIT_MASK_TEST_SW;
	
	
	OUT1_INVALID;	//因为进入菜单时，显示"FF"
	OUT2_INVALID;
}



/////////////////////helper functions
static uint32_t find_int16_cnt(const uint16_t* tbl)
{
	uint32_t idx= 0;
	
	while((uint16_t)-1 != tbl[idx]){
		idx++;
	}
		
	return (idx-1);
}


static uint32_t find_int32_cnt(const uint32_t* tbl)
{
	uint32_t idx= 0;
	
	while((uint32_t)-1 != tbl[idx]){
		idx++;
	}
		
	return (idx-1);
}


static uint32_t find_string_cnt(const char* *tbl_str)
{
	uint32_t idx= 0;
	
	while(strcmp("", tbl_str[idx])){
		idx++;
	}
		
	return (idx-1);
}


static uint32_t find_1d_idx(uint16_t dat)
{
	uint16_t idx_max= find_int16_cnt(_tbl_1d);
	
	for(int i= 0; i<= idx_max; i++){
		if(dat == _tbl_1d[i])
			return i;
	}
	
	return -1;
}


/*开门狗复位。
开启看门狗，设置一个很短时间。之后再死等待。
IWDG->PR默认为0，即divider /4。
Free-running downcouter.
Clocked from an independent RC oscillator(can operate in Standy and Stop modes):32K LSI.参见6.2.6。
Conditional Reset: when the downcounter value becomes less than 0x000。
QQ调试时发现，执行IWDG->KR=0xCCCC，会让RCC_CSR->LSIRDY为1，而RCC_CSR->LSION为0。奇怪QQ
*/
__NO_RETURN void wdg_rst(void)
{
	//实测，不需主动使能LSI，因为在使能IWDG（写入0xCCCC）时，LSIRDY置1。
	RCC->CSR|= RCC_CSR_LSION;
	while(0 == (RCC->CSR & RCC_CSR_LSIRDY));
	

	__disable_irq();			//写上吧。
	
	IWDG->KR= 0xCCCC;			//使能IWDG。
	IWDG->KR= 0x5555;			//使能访问IWDG寄存器。
	
	IWDG->RLR= 0x0001;
	while(IWDG->SR &0x0002);
	
	IWDG->KR= 0xAAAA;			//重载RLR，以加速复位。
	while(1);
}


///*用到的内置外设（TODO需要重写）：
//USART1，USART3，LPUART1，
//SPI2， SPI3，
//TIM2，TIM7，
//SYSTICK。
//*/
//void core_rst(void)
//{
//	__disable_irq();
//	
//	//复位已使用的设备，通过时钟复位。
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_TIM2RST;
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_TIM7RST;
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_SPI2RST;
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_SPI3RST;
//	
//	RCC->APB2RSTR|= RCC_APB2RSTR_USART1RST;
//	RCC->APB1RSTR1|= RCC_APB1RSTR2_LPUART1RST;		//RCC_APB1RSTR2_LPUART1;
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_USART3RST;
//	
//	//Systick关中断
//	NVIC_DisableIRQ(SysTick_IRQn);
//	
//	//__NVIC_SystemReset();
//	
//	while(1);
//}

/*用到的内置外设：
USART1，USART3，LPUART1，
SPI2， SPI3，
TIM2，TIM7，
SYSTICK。
*/
__NO_RETURN void core_rst(void)
{
	__disable_irq();
	
	//复位已使用的设备，通过时钟复位。
	RCC->APB1RSTR1|= RCC_APB1RSTR1_TIM2RST;
	RCC->APB1RSTR1|= RCC_APB1RSTR1_TIM7RST;
	RCC->APB1RSTR1|= RCC_APB1RSTR1_SPI2RST;
	RCC->APB1RSTR1|= RCC_APB1RSTR1_SPI3RST;
	
	RCC->APB2RSTR|= RCC_APB2RSTR_USART1RST;
	RCC->APB1RSTR1|= RCC_APB1RSTR2_LPUART1RST;		//RCC_APB1RSTR2_LPUART1;
	RCC->APB1RSTR1|= RCC_APB1RSTR1_USART3RST;
	
	//Systick关中断
	NVIC_DisableIRQ(SysTick_IRQn);
	
	//__NVIC_SystemReset();	//实测也会复位GPIO。
	__DSB();                                                          /* Ensure all outstanding memory accesses included
																   buffered write are completed before reset */
	SCB->AIRCR  = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos)    |
					   (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
						SCB_AIRCR_VECTRESET_Msk    );         /* Keep priority group unchanged */
	__DSB();                                                          /* Ensure completion of memory access */

	for(;;)                                                           /* wait until reset */
	{
	__NOP();
	}
	
	while(1);
}


/*
*/
void wr_bkp0R(uint32_t dat)
{
	RCC->APB1ENR1|= RCC_APB1ENR1_PWREN;
	PWR->CR1|= PWR_CR1_DBP;
	
	RCC->BDCR|= RCC_BDCR_RTCSEL;			//选择HSE/32 as RTC clock.
	
	RCC->BDCR |= RCC_BDCR_RTCEN;			//使能RTC.
	
	RTC->BKP0R= dat;						//写入
	
	//RCC->BDCR|= RCC_BDCR_BDRST;			//复位BDCR。
	RCC->BDCR &= ~RCC_BDCR_RTCEN;			//使能RTC.
	RCC->APB1ENR1&= ~RCC_APB1ENR1_PWREN;	//关闭PWR时钟。
}

/************************ END OF FILE ************************/
